diff --git a/src/ImageFeatures.jl b/src/ImageFeatures.jl index 1c54bba..216aabf 100644 --- a/src/ImageFeatures.jl +++ b/src/ImageFeatures.jl @@ -1,7 +1,6 @@ __precompile__(true) module ImageFeatures - # package code goes here using Images, ColorTypes, FixedPointNumbers, Distributions using Compat @@ -16,8 +15,9 @@ include("orb.jl") include("freak.jl") include("brisk.jl") include("houghtransform.jl") +include("censure.jl") -export Keypoint, Keypoints, Feature, Features, Params, BRIEF, ORB, FREAK, BRISK +export Keypoint, Keypoints, Feature, Features, Params, BRIEF, ORB, FREAK, BRISK, CENSURE, OctagonFilter, BoxFilter, BiFilter, StarFilter export #Core @@ -68,4 +68,7 @@ export #Circles hough_circle_gradient + + #CENSURE + censure end diff --git a/src/censure.jl b/src/censure.jl new file mode 100644 index 0000000..d874a97 --- /dev/null +++ b/src/censure.jl @@ -0,0 +1,420 @@ +abstract BiFilter + +type BoxFilter <: BiFilter + + scale :: Int + in_length :: Int + out_length :: Int + in_area :: Float64 + out_area :: Float64 + in_weight :: Float64 + out_weight :: Float64 + +end + +type OctagonFilter <: BiFilter + + m_out :: Int + m_in :: Int + n_out :: Int + n_in :: Int + in_area :: Float64 + out_area :: Float64 + in_weight :: Float64 + out_weight :: Float64 + +end + +type StarFilter <: BiFilter + + a_in :: Int + a_out:: Int + in_area :: Float64 + out_area :: Float64 + in_weight :: Float64 + out_weight :: Float64 + +end + +type CENSURE{F} <: Params + + smallest :: Int + largest :: Int + filter_type :: Type{F} + filter_stack :: Array{F} + response_threshold :: Float64 + line_threshold :: Float64 + +end + +function OctagonFilter(mo, mi, no, ni) + OF = OctagonFilter(mo, mi, no, ni, 0.0, 0.0, 0.0, 0.0) + OF.out_area = OF.m_out ^ 2 + 2 * OF.n_out ^ 2 + 4 * OF.m_out * OF.n_out + OF.in_area = OF.m_in ^ 2 + 2 * OF.n_in ^ 2 + 4 * OF.m_in * OF.n_in + OF.out_weight = 1.0 / (OF.out_area - OF.in_area) + OF.in_weight = 1.0 / OF.in_area + OF +end + +function BoxFilter(s) + BF = BoxFilter(s, 2 * s + 1, 4 * s + 1, (2 * s + 1) ^ 2, (4 * s + 1) ^ 2, 0.0, 0.0) + BF.in_weight = 1.0 / BF.in_area + BF.out_weight = 1.0 / (BF.out_area - BF.in_area) + BF +end + +function StarFilter(in, out) + SF = StarFilter(star_filter_sizes[in], star_filter_sizes[out], 0.0, 0.0, 0.0, 0.0) + a_in2=Int(floor(SF.a_in / 2)) + a_out2=Int(floor(SF.a_out / 2)) + SF.in_area = 4 * a_in2 ^ 2 + (2*SF.a_in + 1)^2 + SF.out_area = 4 * a_out2 ^ 2 + (2*SF.a_out + 1)^2 + SF.in_weight = 1.0 / SF.in_area + SF.out_weight = 1.0 / (SF.out_area - SF.in_area) + SF +end + +const octagon_filter_kernels = [[5, 3, 2, 0], + [5, 3, 3, 1], + [7, 3, 3, 2], + [9, 5, 4, 2], + [9, 5, 7, 3], + [13, 5, 7, 4], + [15, 5, 10, 5]] + +const box_filter_kernels = [1, 2, 3, 4, 5, 6, 7] + +const star_filter_kernels = [[2, 1], [4, 2], [5, 3], [6, 4], [8, 5], [9, 6], + [10, 7], [12, 9], [14, 11], [15, 12], [16, 13], [17, 15]] +const star_filter_sizes = [1, 2, 3, 4, 6, 8, 11, 12, 16, 22, 23, 32, 45, 46, 64, 90, 128] + +_getkernel(::Type{BoxFilter}) = box_filter_kernels +_getkernel(::Type{OctagonFilter}) = octagon_filter_kernels +_getkernel(::Type{StarFilter}) = star_filter_kernels + +function _get_filter_stack(filter_type::Type, smallest::Integer, largest::Integer) + k = _getkernel(filter_type) + filter_stack = map(f -> filter_type(f...), k[smallest : largest]) +end + +_get_integral_image(img, filter_type::BoxFilter) = integral_image(img) + +function _get_integral_image(img, filter_type::Union{OctagonFilter, StarFilter}) + img_shape = size(img) + int_img = zeros(img_shape) + right_slant_img = zeros(img_shape) + left_slant_img = zeros(img_shape) + + int_img[1, :] = cumsum(img[1, :]) + right_slant_img[1, :] = int_img[1, :] + left_slant_img[1, :] = int_img[1, :] + + for i in 2:img_shape[1] + sum = 0.0 + for j in 1:img_shape[2] + sum += img[i, j] + int_img[i, j] = sum + int_img[i - 1, j] + left_slant_img[i, j] = sum + right_slant_img[i, j] = sum + + if j > 1 left_slant_img[i, j] += left_slant_img[i - 1, j - 1] end + right_slant_img[i, j] += j < img_shape[2] ? right_slant_img[i - 1, j + 1] : right_slant_img[i - 1, j] + end + end + int_img, right_slant_img, left_slant_img +end + +function _filter_response{T}(int_img::AbstractArray{T, 2}, BF::BoxFilter) + margin = BF.scale * 2 + n = BF.scale + img_shape = size(int_img) + response = zeros(T, img_shape) + R = CartesianRange(CartesianIndex((margin + 2, margin + 2)), CartesianIndex((img_shape[1] - margin, img_shape[2] - margin))) + + for I in R + topleft = I + CartesianIndex(- n - 1, - n - 1) + topright = I + CartesianIndex(- n - 1, n) + bottomleft = I + CartesianIndex(n, - n - 1) + bottomright = I + CartesianIndex(n, n) + A = checkbounds(Bool, int_img, topleft) ? int_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? int_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? int_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? int_img[bottomright] : zero(T) + in_sum = A + D - B - C + + topleft = I + CartesianIndex(- 2 * n - 1, - 2 * n - 1) + topright = I + CartesianIndex(- 2 * n - 1, 2 * n) + bottomleft = I + CartesianIndex(2 * n, - 2 * n - 1) + bottomright = I + CartesianIndex(2 * n, 2 * n) + A = checkbounds(Bool, int_img, topleft) ? int_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? int_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? int_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? int_img[bottomright] : zero(T) + out_sum = A + D - B - C - in_sum + response[I] = out_sum * BF.out_weight - BF.in_weight * in_sum + end + + response +end + +function _filter_response(int_imgs::Tuple, OF::OctagonFilter) + int_img = int_imgs[1] + rs_img = int_imgs[2] + ls_img = int_imgs[3] + + T = eltype(int_img) + + margin = Int(floor(OF.m_out / 2 + OF.n_out)) + m_in2 = Int(floor(OF.m_in / 2)) + m_out2 = Int(floor(OF.m_out / 2)) + + img_shape = size(int_img) + response = zeros(T, img_shape) + R = CartesianRange(CartesianIndex((margin + 2, margin + 2)), CartesianIndex((img_shape[1] - margin, img_shape[2] - margin))) + + for I in R + topleft = I + CartesianIndex(- m_in2 - 1, - m_in2 - OF.n_in - 1) + topright = I + CartesianIndex(- m_in2 - 1, m_in2 + OF.n_in) + bottomleft = I + CartesianIndex(m_in2, - m_in2 - OF.n_in - 1) + bottomright = I + CartesianIndex(m_in2, m_in2 + OF.n_in) + A = checkbounds(Bool, int_img, topleft) ? int_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? int_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? int_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? int_img[bottomright] : zero(T) + in_sum = A + D - B - C + + trap_top_right = bottomright + trap_bot_right = I + CartesianIndex(m_in2 + OF.n_in, m_in2) + trap_top_left = I + CartesianIndex(m_in2, - m_in2 - OF.n_in) + trap_bot_left = I + CartesianIndex(m_in2 + OF.n_in, - m_in2 - 1) + A = checkbounds(Bool, ls_img, trap_top_left) ? ls_img[trap_top_left] : zero(T) + B = checkbounds(Bool, rs_img, trap_top_right) ? rs_img[trap_top_right] : zero(T) + C = checkbounds(Bool, ls_img, trap_bot_left) ? ls_img[trap_bot_left] : zero(T) + D = checkbounds(Bool, rs_img, trap_bot_right) ? rs_img[trap_bot_right] : zero(T) + in_sum += A + D - B - C + + trap_top_right = I + CartesianIndex(- m_in2 - OF.n_in - 1, m_in2 - 1) + trap_top_left = I + CartesianIndex(- m_in2 - OF.n_in - 1, - m_in2) + trap_bot_right = I + CartesianIndex(- m_in2 - 1, m_in2 + OF.n_in - 1) + trap_bot_left = I + CartesianIndex(- m_in2 - 1, - m_in2 - OF.n_in) + A = checkbounds(Bool, rs_img, trap_top_left) ? rs_img[trap_top_left] : zero(T) + B = checkbounds(Bool, ls_img, trap_top_right) ? ls_img[trap_top_right] : zero(T) + C = checkbounds(Bool, rs_img, trap_bot_left) ? rs_img[trap_bot_left] : zero(T) + D = checkbounds(Bool, ls_img, trap_bot_right) ? ls_img[trap_bot_right] : zero(T) + in_sum += A + D - B - C + + topleft = I + CartesianIndex(- m_out2 - 1, - m_out2 - OF.n_out - 1) + topright = I + CartesianIndex(m_out2, - m_out2 - OF.n_out - 1) + bottomleft = I + CartesianIndex(- m_out2 - 1, m_out2 + OF.n_out) + bottomright = I + CartesianIndex(m_out2, m_out2 + OF.n_out) + A = checkbounds(Bool, int_img, topleft) ? int_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? int_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? int_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? int_img[bottomright] : zero(T) + out_sum = A + D - B - C + + trap_top_right = bottomright + trap_bot_right = I + CartesianIndex(m_out2 + OF.n_out, m_out2) + trap_top_left = I + CartesianIndex(m_out2, - m_out2 - OF.n_out) + trap_bot_left = I + CartesianIndex(m_out2 + OF.n_out, - m_out2 - 1) + A = checkbounds(Bool, ls_img, trap_top_left) ? ls_img[trap_top_left] : zero(T) + B = checkbounds(Bool, rs_img, trap_top_right) ? rs_img[trap_top_right] : zero(T) + C = checkbounds(Bool, ls_img, trap_bot_left) ? ls_img[trap_bot_left] : zero(T) + D = checkbounds(Bool, rs_img, trap_bot_right) ? rs_img[trap_bot_right] : zero(T) + out_sum += A + D - B - C + + trap_top_right = I + CartesianIndex(- m_out2 - OF.n_out - 1, m_out2 - 1) + trap_top_left = I + CartesianIndex(- m_out2 - OF.n_out - 1, - m_out2) + trap_bot_right = I + CartesianIndex(- m_out2 - 1, m_out2 + OF.n_out - 1) + trap_bot_left = I + CartesianIndex(- m_out2 - 1, - m_out2 - OF.n_out) + A = checkbounds(Bool, rs_img, trap_top_left) ? rs_img[trap_top_left] : zero(T) + B = checkbounds(Bool, ls_img, trap_top_right) ? ls_img[trap_top_right] : zero(T) + C = checkbounds(Bool, rs_img, trap_bot_left) ? rs_img[trap_bot_left] : zero(T) + D = checkbounds(Bool, ls_img, trap_bot_right) ? ls_img[trap_bot_right] : zero(T) + out_sum += A + D - B - C + out_sum = out_sum - in_sum + + response[I] = in_sum * OF.in_weight - out_sum * OF.out_weight + end + response + +end + +function _filter_response(int_imgs::Tuple, SF::StarFilter) + int_img = int_imgs[1] + rs_img = int_imgs[2] + ls_img = int_imgs[3] + + margin = SF.a_out + Int(floor(SF.a_out/2)) + img_shape = size(int_img) + response = zeros(T, img_shape) + R = CartesianRange(CartesianIndex((margin + 2, margin + 2)), CartesianIndex((img_shape[1] - margin, img_shape[2] - margin))) + + a_in2=Int(floor(SF.a_in/2)) + a_out2=Int(floor(SF.a_out/2)) + + for I in R + #inner star + in_sum=0 + + topleft = I + CartesianIndex(-SF.a_in - a_in2 - 1, -1) + topright = I + CartesianIndex(-SF.a_in - a_in2 - 1, 0) + bottomleft = I + CartesianIndex(-SF.a_in - 1, -a_in2) + bottomright = I + CartesianIndex(-SF.a_in - 1, a_in2 - 1) + A = checkbounds(Bool, int_img, topleft) ? ls_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? rs_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? rs_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? ls_img[bottomright] : zero(T) + in_sum += B + D - A - C + + topleft = I + CartesianIndex(-SF.a_in - 1, -SF.a_in - 1) + topright = I + CartesianIndex(-SF.a_in - 1, SF.a_in) + bottomleft = I + CartesianIndex(-a_in2 , -SF.a_in - 1) + bottomright = I + CartesianIndex(-a_in2 , SF.a_in) + A = checkbounds(Bool, int_img, topleft) ? int_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? int_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? int_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? int_img[bottomright] : zero(T) + in_sum += A + D - B - C + + topleft = bottomleft + topright = bottomright + bottomleft = I + CartesianIndex(0, -SF.a_in - a_in2 - 1) + bottomright = I + CartesianIndex(0, SF.a_in + a_in2) + A = checkbounds(Bool, int_img, topleft) ? rs_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? ls_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? rs_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? ls_img[bottomright] : zero(T) + in_sum += A + D - B - C + + topleft = bottomleft + topright = bottomright + bottomleft = I + CartesianIndex(a_in2 - 1, -SF.a_in - 2) + bottomright = I + CartesianIndex(a_in2 - 1, SF.a_in + 1) + A = checkbounds(Bool, int_img, topleft) ? ls_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? rs_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? ls_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? rs_img[bottomright] : zero(T) + in_sum += A + D - B - C + + topleft = I + CartesianIndex(a_in2 - 1, -SF.a_in - 1) + topright = I + CartesianIndex(a_in2 - 1, SF.a_in) + bottomleft = I + CartesianIndex(SF.a_in, -SF.a_in - 1) + bottomright = I + CartesianIndex(SF.a_in, SF.a_in) + A = checkbounds(Bool, int_img, topleft) ? int_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? int_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? int_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? int_img[bottomright] : zero(T) + in_sum += A + D - B - C + + topleft = I + CartesianIndex(SF.a_in , - a_in2 - 1) + topright = I + CartesianIndex(SF.a_in , a_in2) + bottomleft = I + CartesianIndex(SF.a_in + a_in2, -1) + bottomright = I + CartesianIndex(SF.a_in + a_in2, 0) + A = checkbounds(Bool, int_img, topleft) ? ls_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? rs_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? ls_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? rs_img[bottomright] : zero(T) + in_sum += A + D - B - C + + #outer star + out_sum=0 + + topleft = I + CartesianIndex(-SF.a_out - a_out2 - 1, -1) + topright = I + CartesianIndex(-SF.a_out - a_out2 - 1, 0) + bottomleft = I + CartesianIndex(-SF.a_out - 1, -a_out2) + bottomright = I + CartesianIndex(-SF.a_out - 1, a_out2 - 1) + A = checkbounds(Bool, int_img, topleft) ? ls_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? rs_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? rs_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? ls_img[bottomright] : zero(T) + out_sum += B + D - A - C + + topleft = I + CartesianIndex(-SF.a_out - 1, -SF.a_out - 1) + topright = I + CartesianIndex(-SF.a_out - 1, SF.a_out) + bottomleft = I + CartesianIndex(-a_out2 , -SF.a_out - 1) + bottomright = I + CartesianIndex(-a_out2 , SF.a_out) + A = checkbounds(Bool, int_img, topleft) ? int_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? int_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? int_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? int_img[bottomright] : zero(T) + out_sum += A + D - B - C + + topleft = bottomleft + topright = bottomright + bottomleft = I + CartesianIndex(0, -SF.a_out - a_out2 - 1) + bottomright = I + CartesianIndex(0, SF.a_out + a_out2) + A = checkbounds(Bool, int_img, topleft) ? rs_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? ls_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? rs_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? ls_img[bottomright] : zero(T) + out_sum += A + D - B - C + + topleft = bottomleft + topright = bottomright + bottomleft = I + CartesianIndex(a_out2 - 1, -SF.a_out - 2) + bottomright = I + CartesianIndex(a_out2 - 1, SF.a_out + 1) + A = checkbounds(Bool, int_img, topleft) ? ls_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? rs_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? ls_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? rs_img[bottomright] : zero(T) + out_sum += A + D - B - C + + topleft = I + CartesianIndex(a_out2 - 1, -SF.a_out - 1) + topright = I + CartesianIndex(a_out2 - 1, SF.a_out) + bottomleft = I + CartesianIndex(SF.a_out, -SF.a_out - 1) + bottomright = I + CartesianIndex(SF.a_out, SF.a_out) + A = checkbounds(Bool, int_img, topleft) ? int_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? int_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? int_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? int_img[bottomright] : zero(T) + out_sum += A + D - B - C + + topleft = I + CartesianIndex(SF.a_out , - a_out2 - 1) + topright = I + CartesianIndex(SF.a_out , a_out2) + bottomleft = I + CartesianIndex(SF.a_out + a_out2, -1) + bottomright = I + CartesianIndex(SF.a_out + a_out2, 0) + A = checkbounds(Bool, int_img, topleft) ? ls_img[topleft] : zero(T) + B = checkbounds(Bool, int_img, topright) ? rs_img[topright] : zero(T) + C = checkbounds(Bool, int_img, bottomleft) ? ls_img[bottomleft] : zero(T) + D = checkbounds(Bool, int_img, bottomright) ? rs_img[bottomright] : zero(T) + out_sum += A + D - B - C + + out_sum = out_sum - in_sum + response[I] = out_sum * SF.out_weight - SF.in_weight * in_sum + end + + response +end + +function CENSURE(; smallest::Integer = 1, largest::Integer = 7, filter::Type = BoxFilter, response_threshold::Number = 0.15, line_threshold::Number = 10) + CENSURE{filter}(smallest, largest, filter, _get_filter_stack(filter, smallest, largest), response_threshold, line_threshold) +end + +function censure{T, F}(img::AbstractArray{T, 2}, params::CENSURE{F}) + int_img = _get_integral_image(img, params.filter_stack[1]) + responses = map(f -> _filter_response(int_img, f), params.filter_stack) + response_matrix = reshape(hcat(responses...), size(img)..., size(responses)...) + minima, maxima = extrema_filter(convert(Array{Float64}, padarray(response_matrix, [1, 1, 1], [1, 1, 1], "replicate")), [3, 3, 3]) + features = map(i -> (minima[i] == response_matrix[i] || maxima[i] == response_matrix[i]) && ( response_matrix[i] > params.response_threshold ), CartesianRange(size(response_matrix))) + (grad_x, grad_y) = imgradients(img, "sobel", "replicate") + cov_xx = grad_x .* grad_x + cov_xy = grad_x .* grad_y + cov_yy = grad_y .* grad_y + for i in 1:params.largest - params.smallest + 1 + gamma = (1 + (params.smallest + i - 1) / 3.0) + filt_cov_xx = imfilter_gaussian(cov_xx, [gamma, gamma]) + filt_cov_xy = imfilter_gaussian(cov_xy, [gamma, gamma]) + filt_cov_yy = imfilter_gaussian(cov_yy, [gamma, gamma]) + + features[:, :, i] = map((xx, yy, xy, f) -> (xx + yy) ^ 2 > params.line_threshold * (xx * yy - xy ^ 2) ? false : f, filt_cov_xx, filt_cov_yy, filt_cov_xy, features[:, :, i]) + end + keypoints = Array{Keypoint}([]) + scales = Array{Integer}([]) + for scale in 1:(params.largest - params.smallest + 1) + rows, cols, _ = findnz(features[:, :, scale]) + append!(keypoints, map((r, c) -> Keypoint(r, c), rows, cols)) + append!(scales, ones(length(rows)) * scale) + end + keypoints, scales +end \ No newline at end of file diff --git a/test/censure.jl b/test/censure.jl new file mode 100644 index 0000000..3794eee --- /dev/null +++ b/test/censure.jl @@ -0,0 +1,110 @@ +using Images, Base.Test, ImageFeatures + +@testset "CENSURE" begin + + @testset "Filters" begin + + bf = BoxFilter(1) + @test bf.scale == 1 + @test bf.in_length == 3 + @test bf.out_length == 5 + @test bf.in_area == 9.0 + @test bf.out_area == 25.0 + @test isapprox(bf.in_weight, 1 / 9) == true + @test isapprox(bf.out_weight, 1 / 16) == true + bf = BoxFilter(5) + @test bf.scale == 5 + @test bf.in_length == 11 + @test bf.out_length == 21 + @test bf.in_area == 121.0 + @test bf.out_area == 441.0 + @test isapprox(bf.in_weight, 1 / 121) == true + @test isapprox(bf.out_weight, 1 / 320) == true + + of = OctagonFilter(5, 3, 2, 0) + @test of.m_out == 5 + @test of.m_in == 3 + @test of.n_out == 2 + @test of.n_in == 0 + @test of.in_area == 9.0 + @test of.out_area == 73.0 + @test isapprox(of.in_weight, 1 / 9) == true + @test isapprox(of.out_weight, 1 / 64) == true + + of = OctagonFilter(13, 5, 7, 4) + @test of.m_out == 13 + @test of.m_in == 5 + @test of.n_out == 7 + @test of.n_in == 4 + @test of.in_area == 137.0 + @test of.out_area == 631.0 + @test isapprox(of.in_weight, 1 / 137) == true + @test isapprox(of.out_weight, 1 / 494) == true + + end + + @testset "Integral Image" begin + + img = ones(5, 5) + bf = BoxFilter(1) + @test all(integral_image(img) .== ImageFeatures._get_integral_image(img, bf)) == true + + of = OctagonFilter(5, 3, 2, 0) + i, rs, ls = ImageFeatures._get_integral_image(img, of) + @test all(i .== integral_image(img)) == true + r_check = [ 1.0 2.0 3.0 4.0 5.0 + 3.0 5.0 7.0 9.0 10.0 + 6.0 9.0 12.0 14.0 15.0 + 10.0 14.0 17.0 19.0 20.0 + 15.0 19.0 22.0 24.0 25.0 ] + @test all(rs .== r_check) == true + l_check = [ 1.0 2.0 3.0 4.0 5.0 + 1.0 3.0 5.0 7.0 9.0 + 1.0 3.0 6.0 9.0 12.0 + 1.0 3.0 6.0 10.0 14.0 + 1.0 3.0 6.0 10.0 15.0 ] + @test all(ls .== l_check) == true + + end + + @testset "Filter Response" begin + + img = [4.0 2.0 6.0 1.0 1.0 8.0 2.0; + 9.0 3.0 8.0 3.0 5.0 8.0 4.0; + 4.0 10.0 6.0 2.0 5.0 1.0 5.0; + 10.0 5.0 8.0 6.0 6.0 3.0 3.0; + 5.0 6.0 4.0 8.0 3.0 3.0 9.0; + 3.0 1.0 5.0 6.0 2.0 2.0 2.0; + 9.0 3.0 4.0 1.0 10.0 8.0 6.0] + bf = BoxFilter(1) + response = ImageFeatures._filter_response(ImageFeatures._get_integral_image(img, bf), bf) + @test isapprox(response[4, 4], -0.895833, rtol = 0.001) == true + @test isapprox(response[4, 5], 0.888889, rtol = 0.001) == true + @test isapprox(response[5, 4], -0.958333, rtol = 0.001) == true + @test isapprox(response[5, 5], 0.604167, rtol = 0.001) == true + @test all(response[:, 1:3] .== 0) == true + @test all(response[1:3, :] .== 0) == true + @test all(response[:, 6:6] .== 0) == true + @test all(response[6:7, :] .== 0) == true + + img = [ 3.0 5.0 8.0 8.0 5.0 4.0 1.0 + 3.0 8.0 6.0 10.0 1.0 5.0 4.0 + 10.0 1.0 6.0 4.0 10.0 4.0 5.0 + 2.0 10.0 9.0 4.0 5.0 3.0 7.0 + 1.0 7.0 5.0 9.0 7.0 6.0 3.0 + 5.0 6.0 9.0 9.0 1.0 4.0 8.0 + 2.0 4.0 6.0 9.0 8.0 4.0 10.0] + response = ImageFeatures._filter_response(ImageFeatures._get_integral_image(img, bf), bf) + @test isapprox(response[4, 4], -0.93056, rtol = 0.001) == true + @test isapprox(response[4, 5], -0.02777, rtol = 0.001) == true + @test isapprox(response[5, 4], -0.69444, rtol = 0.001) == true + @test isapprox(response[5, 5], 1.35417, rtol = 0.001) == true + @test all(response[:, 1:3] .== 0) == true + @test all(response[1:3, :] .== 0) == true + @test all(response[:, 6:6] .== 0) == true + @test all(response[6:7, :] .== 0) == true + + + end + +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 85d3e66..0850395 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -56,6 +56,7 @@ tests = [ "freak.jl", "brisk.jl", "houghtransform.jl", + "censure.jl", ] for t in tests