BlockMatching.FullSearchType
FullSearch(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().

Note

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_matchMethod
best_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.

Note

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. See subtypes(BlockMatching.AbstractBlockMatchingStrategy) for possible strategies.
  • ref::AbstractArray: required Reference image where the matched pixel q belongs to.
  • frame::AbstractArray: optional The current image/frame where the input pixel p belongs to. If frame is not provided, it will be ref.
  • p::CartesianIndex: optional The given pixel p that block matching operates on. If not provided, block matching is operating on the whole image and thus returns an array of pixels qs.

Parameters

  • offset::Bool: optional if true, it returns the motion vector q-p instead of the pixel q. The default value is false.

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 qs 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 qs 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
Tip

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_matchMethod
multi_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 qs 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. See subtypes(BlockMatching.AbstractBlockMatchingStrategy) for possible strategies.
  • ref::AbstractArray: required Reference image where the matched pixel q belongs to.
  • frame::AbstractArray: optional The current image/frame where the input pixel p belongs to. If frame is not provided, it will be ref.
  • p::CartesianIndex: optional The given pixel p that block matching operates on. If not provided, block matching is operating on the whole image and thus returns an array of pixels qs.

Parameters

  • num_patches: required The number of matched pixels. If the candidates number is smaller than num_patches, the behavior is undefined; it may or may not throw errors.
  • offset::Bool: optional if true, it returns the motion vector q-p instead of the pixel q. The default value is false.

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 qs 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 qs 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
Tip

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_cartesianMethod
to_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.topkMethod
topk(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