BlockMatching.FullSearch
— TypeFullSearch(d=Cityblock(), N; patch_radius, search_radius, search_stride=1)
Construct a block matching algorithm with full search strategy. In some literature, this is also called exhaustive search.
The default patch distance is Distances.Cityblock()
.
If p
is not given and if inputs are CuArray
then GPU methods will be applied for a small set of predefined distances from Distances.jl. The result will be slightly different from its CPU version.
BlockMatching.best_match
— Methodbest_match(S::AbstractBlockMatchingStrategy, ref, [frame=ref]; offset=false)
best_match(S::AbstractBlockMatchingStrategy, ref, [frame=ref], p; offset=false)
For given pixel p
in frame
, find the best match pixel q
in ref
with block matching strategy S
. If p
is not provided, it operates on all pixels p ∈ CartesianIndices(ref)
and returns an array.
For clarification, "pixel" here means the position CartesianIndex
instead of the value Colorant
.
Arguments
S::AbstractBlockMatchingStrategy
: required The concrete block matching strategy and relevant configs, e.g., patch size, search window size. Seesubtypes(BlockMatching.AbstractBlockMatchingStrategy)
for possible strategies.ref
::AbstractArray: required Reference image where the matched pixelq
belongs to.frame::AbstractArray
: optional The current image/frame where the input pixelp
belongs to. Ifframe
is not provided, it will beref
.p::CartesianIndex
: optional The given pixelp
that block matching operates on. If not provided, block matching is operating on the whole image and thus returns an array of pixelsq
s.
Parameters
offset::Bool
: optional iftrue
, it returns the motion vectorq-p
instead of the pixelq
. The default value isfalse
.
Output
If p
is given, it returns CartesianIndex{N}
. Otherwise the block matching operates on the whole image and returns Array{CartesianIndex{N}, N}
, i.e., the motion field.
Examples
If pixel p
is provided, block matching only operates on the given pixel, the output is the matched pixels q
s for p
.
using Images, TestImages
using BlockMatching
ref = imresize(testimage("cameraman"), (64, 64))
img = imrotate(ref, 0.2, CartesianIndices(ref).indices)
S = FullSearch(SqEuclidean(), ndims(img), patch_radius=5, search_radius=11)
p = CartesianIndex(17, 17)
best_match(S, img, ref, p)
# output
CartesianIndex(17, 14)
If p
is not provided, the block matching operates on the whole image. Each item of the output array is the matched pixels q
s for p
, i.e., best_match(S, ref, frame)[p] = best_match(S, ref, frame, p)
.
julia> matches = best_match(S, img, ref);
julia> summary(matches)
"64×64 Matrix{CartesianIndex{2}}"
julia> matches[p] == best_match(S, img, ref, p)
true
best_match(S, ref, frame)
is usually more performant than map(p->best_match(S, ref, frame, p), CartesianIndices(frame))
because intermediate results can be cached/pre-allocated so as to reduce unnecessary computation and memory allocation.
See also
multi_match
can be used when multiple candidates are wanted.
BlockMatching.multi_match
— Methodmulti_match(S::AbstractBlockMatchingStrategy, ref, [frame=ref]; num_patches, offset=true)
multi_match(S::AbstractBlockMatchingStrategy, ref, [frame=ref], p::CartesianIndex; num_patches, offset=true)
For given pixel p
in frame
, find matched pixels q
s in ref
with block matching strategy S
.
Arguments
S::AbstractBlockMatchingStrategy
: required The concrete block matching strategy and relevant configs, e.g., similarity mesaure, patch size, search window size. Seesubtypes(BlockMatching.AbstractBlockMatchingStrategy)
for possible strategies.ref
::AbstractArray: required Reference image where the matched pixelq
belongs to.frame::AbstractArray
: optional The current image/frame where the input pixelp
belongs to. Ifframe
is not provided, it will beref
.p::CartesianIndex
: optional The given pixelp
that block matching operates on. If not provided, block matching is operating on the whole image and thus returns an array of pixelsq
s.
Parameters
num_patches
: required The number of matched pixels. If the candidates number is smaller thannum_patches
, the behavior is undefined; it may or may not throw errors.offset::Bool
: optional iftrue
, it returns the motion vectorq-p
instead of the pixelq
. The default value isfalse
.
Output
If p
is given, it returns Vector{CartesianIndex{N}}
. Otherwise the block matching operates on the whole image and returns Array{CartesianIndex{N}, N+1}
, where the extra N+1 dimension stores the matched vector.
Examples
If pixel p
is provided, block matching only operates on the given pixel, the output is the matched pixels q
s for p
.
using Images, TestImages
using BlockMatching
ref = imresize(testimage("cameraman"), (64, 64))
img = imrotate(ref, 0.2, CartesianIndices(ref).indices)
S = FullSearch(SqEuclidean(), ndims(img), patch_radius=5, search_radius=11)
p = CartesianIndex(17, 17)
multi_match(S, img, ref, p; num_patches=2)
# output
2-element Vector{CartesianIndex{2}}:
CartesianIndex(17, 14)
CartesianIndex(18, 13)
Otherwise, the block matching operates on the whole image. Each item of the output array is the matched pixels q
s for p
, i.e., multi_match(S, ref, frame)[p] = multi_match(S, ref, frame, p)
.
julia> matches = multi_match(S, img, ref; num_patches=2);
julia> summary(matches)
"64×64 Matrix{Vector{CartesianIndex{2}}}"
julia> matches[p, :] == multi_match(S, img, ref, p; num_patches=2)
true
multi_match(S, ref, frame)
is usually more performant than map(p->multi_match(S, ref, frame, p), CartesianIndices(frame))
because intermediate results can be cached so as to reduce computation and memory allocation.
See also
best_match
is more performant a choice when num_patches==1
. It also supports more sophisticated strategies, e.g., ThreeStepSearch.
BlockMatching.to_cartesian
— Methodto_cartesian(N, args::Index...)
Convert args
to a tuple of CartesianIndex{N}
. Each item in args
is either Int
, NTuple{N, Int}
or CartesianIndex{N}
; if it is Int
it will be repeated, i.e., ntuple(_->i, N)
.
Examples
julia> to_cartesian(2, 3, 1, 4)
(CartesianIndex(3, 3), CartesianIndex(1, 1), CartesianIndex(4, 4))
julia> to_cartesian(2, CartesianIndex(1, 3), 1, (4, 4))
(CartesianIndex(1, 3), CartesianIndex(1, 1), CartesianIndex(4, 4))
BlockMatching.topk
— Methodtopk(data, K, o=Forward) -> (vals, inds)
Given input data
, find the largest K
numbers vals
and their associated indices inds
. If o=Base.Order.Reverse
, then it's the lowest K
numbers.
julia> data = rand(1:20, 20);
julia> vals, inds = BlockMatching.topk(data, 5)
([3, 13, 10, 19, 13], [5, 4, 1, 3, 2])
julia> data[inds] == vals
true