Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

imresize/imrotate fixed point #129

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/ImageTransformations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ export
warpedview,
InvWarpedView,
invwarpedview,
imrotate
imrotate,
CenterPoint

include("centerpoint.jl")
include("autorange.jl")
include("interpolations.jl")
include("warp.jl")
Expand Down
16 changes: 16 additions & 0 deletions src/centerpoint.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
CenterPoint(dims) -> cp

Create a fixed point which can be used in `imresize` and `imrotate`
functions in order to keep the value in this point the same, i.e.,

```julia
img[cp] == imgr[cp]
```
"""
struct CenterPoint{N}
p::CartesianIndex{N}
end

CenterPoint(dims::Dims{N}) where N = CenterPoint{N}(CartesianIndex(dims))
CenterPoint(dims::Int64...) = CenterPoint(Tuple(dims))
21 changes: 20 additions & 1 deletion src/resizing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ upsample/downsample the image `img` to a given size `sz` or axes `inds` using in
The output size is `ceil(Int, size(img).*ratio)`. If `ratio` is larger than `1`, it is
an upsample operation. Otherwise it is a downsample operation. `ratio` can also be a tuple,
in which case `ratio[i]` specifies the resize ratio at dimension `i`.
- `method::InterpolationType`:
- `method::InterpolationType`:
specify the interpolation method used for reconstruction. conveniently, `methold` can
also be a `Degree` type, in which case a `BSpline` object will be created.
For example, `method = Linear()` is equivalent to `method = BSpline(Linear())`.
Expand All @@ -83,6 +83,10 @@ imresize(img, (1:256, )) # 256*768
imresize(img, ratio = 0.5) #256*384
imresize(img, ratio = (2, 1)) # 1024*768

# pass `CenterPoint`
imresize(img, (256, 384), CenterPoint(10, 15)) # 256*384, img[10,15] ≈ imgr[10,15]
imresize(img, CenterPoint(10, 15), ratio = 0.5) # 256*384, img[10,15] ≈ imgr[10,15]

# use different interpolation method
imresize(img, (256, 384), method=Linear()) # 256*384 bilinear interpolation
imresize(img, (256, 384), method=Lanczos4OpenCV()) # 256*384 OpenCV-compatible Lanczos 4 interpolation
Expand Down Expand Up @@ -120,6 +124,21 @@ function imresize(original::AbstractArray{T,N}, new_inds::Indices{N}; kwargs...)
end
end

function imresize(original::AbstractArray{T,N}, new_size::Dims{N}, center_point::CenterPoint{N}; kwargs...) where {T,N}
Tnew = imresize_type(first(original))
cp = center_point.p
checkbounds(original, cp)
topleft = firstindex.(Ref(original), Tuple(1:N))
offset = @. cp.I - new_size * (cp.I - topleft) ÷ $size(original) - 1
newimage = OffsetArray(similar(original, Tnew, new_size), offset)
imresize!(newimage, original; kwargs...)
end

function imresize(original::AbstractArray{T,N}, center_point::CenterPoint{N}; ratio, kwargs...) where {T,N}
all(ratio .> 0) || throw(ArgumentError("ratio $ratio should be positive"))
new_size = ceil.(Int, size(original) .* ratio) # use ceil to avoid 0
imresize(original, new_size, center_point; kwargs...)
end
# To choose the output type, rather than forcing everything to
# Float64 by multiplying by 1.0, we exploit the fact that the scale
# changes correspond to integer ratios. We mimic ratio arithmetic
Expand Down
32 changes: 32 additions & 0 deletions test/resizing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,23 @@ end
test_imresize_interface(img, (5,10), (5,))
test_imresize_interface(img, (5,10), 1:5) # FIXME: @inferred failed
test_imresize_interface(img, (5,10), (1:5,)) # FIXME: @inferred failed
test_imresize_interface(img, (5,5), (5,5), CenterPoint(1, 1))
test_imresize_interface(img, (20,20), CenterPoint(1, 1), ratio = 2)
test_imresize_interface(img, (20,10), CenterPoint(1, 1), ratio = (2, 1))
Comment on lines +50 to +52
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only makes sure the function gets called and outputs something. We also need to test if the output is correct, for example:

  • test if imresize(img, (20,20), CenterPoint(1, 1)) works the same as imresize(img, (20,20))
  • test if imresize(img, (20, 20), CenterPoint(5, 5); method=Constant())[5, 5] == img[5, 5] (If I'm right about the implementation, I'm not sure if it's [5, 5] here).
  • If it's not supported, test if imresize(imag, (20, 20), CenterPoint(-10, -10)) errors.

Also, OffsetArray is used widely in the ecosystem, so it would be great to also test OffsetArray(img, -1, -1) works normally for the above test cases.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About testing if the CenterPoint doesn't change, without overriding the value it can be actully quite different, so either we should override it or it won't be ensured. Except this point I'm working on it.

Copy link
Member

@johnnychen94 johnnychen94 Jul 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I also noticed this. BSpline(Constant()) is the nearest interpolation, I believe by using this method, it won't doesn't change the value?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's right.


@test_throws MethodError imresize(img,5.0,5.0)
@test_throws MethodError imresize(img,(5.0,5.0))
@test_throws MethodError imresize(img,(5, 5.0))
@test_throws MethodError imresize(img,[5,5])
@test_throws UndefKeywordError imresize(img)
@test_throws UndefKeywordError imresize(img, CenterPoint(1, 1))
@test_throws DimensionMismatch imresize(img,(5,5,5))
@test_throws ArgumentError imresize(img, ratio = -0.5)
@test_throws ArgumentError imresize(img, ratio = (-0.5, 1))
@test_throws ArgumentError imresize(img, CenterPoint(1, 1), ratio = -0.5)
@test_throws DimensionMismatch imresize(img, ratio=(5,5,5))
@test_throws DimensionMismatch imresize(img, (5,5,1))
@test_throws BoundsError imresize(img, (5,5), CenterPoint(100, 100))
end
end

Expand Down Expand Up @@ -149,6 +155,32 @@ end
out = imresize(img, (0:127, 0:127), method=Lanczos4OpenCV())
@test axes(out) == (0:127, 0:127)
@test OffsetArrays.no_offset_view(out) == imresize(img, (128, 128), method=Lanczos4OpenCV())

@test imresize(img, (128,128), method=Linear()) == imresize(img, (128,128), CenterPoint(1,1), method=Linear())
@test imresize(img, (128,128), method=BSpline(Linear())) == imresize(img, (128,128), CenterPoint(1,1), method=BSpline(Linear()))
@test imresize(img, (128,128), method=Lanczos4OpenCV()) == imresize(img, (128,128), CenterPoint(1,1), method=Lanczos4OpenCV())

out = imresize(OffsetArray(img, -1, -1), (128,128), CenterPoint(1,1), method=Linear())
@test imresize(img, (128,128), method=Linear()) == OffsetArrays.no_offset_view(out)

out = imresize(OffsetArray(img, -1, -1), (128,128), CenterPoint(1,1), method=BSpline(Linear()))
@test imresize(img, (128,128), method=BSpline(Linear())) == OffsetArrays.no_offset_view(out)

out = imresize(OffsetArray(img, -1, -1), (128,128), CenterPoint(1,1), method=Lanczos4OpenCV())
@test imresize(img, (128,128), method=Lanczos4OpenCV()) == OffsetArrays.no_offset_view(out)

#check negative CenterPoint
out = imresize(OffsetArray(img, -2, -2), (128,128), CenterPoint(-1,-1), method=Linear())
@test imresize(img, (128,128), method=Linear()) == OffsetArrays.no_offset_view(out)

out = imresize(OffsetArray(img, -2, -2), (128,128), CenterPoint(-1,-1), method=BSpline(Linear()))
@test imresize(img, (128,128), method=BSpline(Linear())) == OffsetArrays.no_offset_view(out)

out = imresize(OffsetArray(img, -2, -2), (128,128), CenterPoint(-1,-1), method=Lanczos4OpenCV())
@test imresize(img, (128,128), method=Lanczos4OpenCV()) == OffsetArrays.no_offset_view(out)

#check CenterPoint consistency
@test imresize(img, (128, 128), CenterPoint(5, 5), method=Constant())[5,5] == img[5,5]
end
end

Expand Down