# Translate images by subpixel amounts

**URL:** <https://discourse.julialang.org/t/translate-images-by-subpixel-amounts/30248>\
**Category:** General Usage\
**Tags:** images, fftw, dsp\
**Created:** [October 23, 2019, 10:07pm UTC](https://discourse.julialang.org/t/translate-images-by-subpixel-amounts/30248 "2019-10-23T22:07:39Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![johnheyer](https://avatars.discourse-cdn.com/v4/letter/j/a8b319/32.png) [@johnheyer](https://discourse.julialang.org/u/johnheyer)\
**Post date:** [October 23, 2019, 10:07pm UTC](https://discourse.julialang.org/t/translate-images-by-subpixel-amounts/30248/1 "2019-10-23T22:07:39Z")

</div>

Hello,

I’m trying to translate an image by arbitrary amounts, and am currently doing translations via JuliaImages and CoordinateTransformation packages as such:

```julia
t = Translation(y_shift, x_shift)
img = warp(img, t, indices_spatial(img), 0)

```

However, this requires that `y_shift` and `x_shift` are integers. I am wondering if there is support for non-integer translation via interpolation. Is there a way to use warp with any affine transformation? Is there a better way than warp?

Thanks!

---

<div class="post-metadata">

**Author:** ![ssfrr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ssfrr/32/3736_2.png) [@ssfrr](https://discourse.julialang.org/u/ssfrr)\
**Post date:** [October 24, 2019, 2:53am UTC](https://discourse.julialang.org/t/translate-images-by-subpixel-amounts/30248/2 "2019-10-24T02:53:39Z")

</div>

For 1D signals you can do the translation in the frequency domain, which corresponds to a circular shift. With the proper zero-padding you can do a non-circular shift.

```julia
using FFTW: rfft, irfft
using Plots: plot
using DSP: resample
julia> x = randn(50);

julia> function fftshift(x, d)
           L = length(x)
           irfft(rfft(x) .* exp.(-im * d .* range(0, π, length=L÷2+1)), L)
       end
fftshift (generic function with 1 method)

# zero-pad by more than your shift amount
julia> xpad = [x;0];

julia> x2 = fftshift(xpad, 0.4);

# upsample for plotting so you can see between samples
julia> plot([resample(xpad, 8) resample(x2, 8)])

```

 ![image](https://global.discourse-cdn.com/julialang/original/3X/0/d/0d8b781bb0017e9dbd35c1d331347b7a12646b22.png)

You should be able to do something similar using a 2D FFT.

---

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [October 25, 2019, 5:02pm UTC](https://discourse.julialang.org/t/translate-images-by-subpixel-amounts/30248/3 "2019-10-25T17:02:26Z")

</div>

> [@johnheyer](#):
>
> However, this requires that `y_shift` and `x_shift` are integers.

Not for me (just curious, where did you get that idea?):

```julia
julia> t = Translation(0.2, -1.4)

julia> imgs = warp(img, t, indices_spatial(img));

```

If you want something beyond linear interpolation, try e.g.,

```julia
imgs = warp(float.(img), t, indices_spatial(img), Quadratic(Flat(OnCell())), 0)

```

The `float` may be necessary if `img` itself has a restrictive `eltype`, to ensure that you can represent the output appropriately.

---

<div class="post-metadata">

**Author:** ![johnheyer](https://avatars.discourse-cdn.com/v4/letter/j/a8b319/32.png) [@johnheyer](https://discourse.julialang.org/u/johnheyer)\
**Post date:** [October 25, 2019, 8:29pm UTC](https://discourse.julialang.org/t/translate-images-by-subpixel-amounts/30248/4 "2019-10-25T20:29:00Z")

</div>

Hi @tim.holy, thanks for the response!

I can’t even reproduce the exact error I was getting from my program anymore 😅. However, my first thought was that it was because integer coordinate transformations were required, and adding `x_shift, y_shift = round(x_shift), round(y_shift)`, translations began to work.

Of course, I didn’t just take this as truth and did some testing in the REPL. Turns out that my toy tests were bad because my “images” were integer arrays, and that only seems to work with certain translations. For example

```julia
julia> a = [1 2 3; 4 5 6];

julia> t = Translation(.75, .75);

julia> b = warp(a, t, indices_spatial(a), 0); # works

julia> t = Translation(.9, .9);

julia> b = warp(a, t, indices_spatial(a), 0); # doesn't work
ERROR: InexactError: Int64(4.6000000000000005)
Stacktrace:
 [1] Type at ./float.jl:703 [inlined]
 [2] convert at ./number.jl:7 [inlined]
 [3] setindex! at ./array.jl:768 [inlined]
 [4] setindex! at ./multidimensional.jl:488 [inlined]
 [5] warp!(::Array{Int64,2}, ::Interpolations.FilledExtrapolation{Int64,2,Interpolations.BSplineInterpolation{Int64,2,Array{Int64,2},BSpline{Linear},Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}},BSpline{Linear},Int64}, ::Translation{StaticArrays.SArray{Tuple{2},Float64,1,2}}) at /Users/John/.juliapro/JuliaPro_v1.2.0-1/packages/ImageTransformations/7wC0C/src/warp.jl:89
 [6] warp at /Users/John/.juliapro/JuliaPro_v1.2.0-1/packages/ImageTransformations/7wC0C/src/warp.jl:84 [inlined]
 [7] warp(::Array{Int64,2}, ::Translation{StaticArrays.SArray{Tuple{2},Float64,1,2}}, ::Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}, ::Int64) at /Users/John/.juliapro/JuliaPro_v1.2.0-1/packages/ImageTransformations/7wC0C/src/warp.jl:96
 [8] top-level scope at none:0

julia> b = warp(float.(a), t, indices_spatial(a), 0); # now works!

```

So, my testing in the REPL falsely led me to believe that integer shifts were required. I wish I could reproduce the error I was having in my program, however, because the image was already `float` values.

I do have another question tho. I am looking at the docs and it says there are descriptions of the boundary condition methods under /doc/latex, but I cannot find that in the repo, and I can’t understand the different interpolation methods such as `Quadratic(Flat(OnCell()))`.

The behavior I am looking for is:

```julia
a = [1 2; 3 4]
t = Translation(.5, .5) 

```

^ just noticed that this also does not work without float casting, and this was probably the example that I first tried and saw InexactError (2.5)

```julia
b = warp(a, t, indices_spatial(a), 0)
[2.5 1.5; 1.75 1]

```

However, the edge pixels become zeros. Is there a method to produce the behavior above?

---

<div class="post-metadata">

**Author:** ![johnheyer](https://avatars.discourse-cdn.com/v4/letter/j/a8b319/32.png) [@johnheyer](https://discourse.julialang.org/u/johnheyer)\
**Post date:** [October 25, 2019, 8:31pm UTC](https://discourse.julialang.org/t/translate-images-by-subpixel-amounts/30248/5 "2019-10-25T20:31:45Z")

</div>

Sorry, I meant to respond to this @ssfrr. I really appreciate it. Although I was not able to implement a solution using FFT myself.

---

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [January 20, 2020, 11:11am UTC](https://discourse.julialang.org/t/translate-images-by-subpixel-amounts/30248/6 "2020-01-20T11:11:21Z")

</div>

Somehow I stumbled across this again. Fixed in [https://github.com/JuliaImages/ImageTransformations.jl/pull/88](https://github.com/JuliaImages/ImageTransformations.jl/pull/88) (released as version 0.8.3)
