From 088648cae9778ded766fdff9414ea8927dbf6c7a Mon Sep 17 00:00:00 2001 From: mronian Date: Thu, 30 Jun 2016 01:38:39 +0530 Subject: [PATCH 1/7] Adds Core functions, datatypes and Filters for CENSURE --- src/ImageFeatures.jl | 9 ++++-- src/censure.jl | 65 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 src/censure.jl diff --git a/src/ImageFeatures.jl b/src/ImageFeatures.jl index 3f50310..2b99262 100644 --- a/src/ImageFeatures.jl +++ b/src/ImageFeatures.jl @@ -1,5 +1,4 @@ module ImageFeatures - # package code goes here using Images, ColorTypes, FixedPointNumbers, Distributions @@ -12,8 +11,9 @@ include("brief.jl") include("orb.jl") include("freak.jl") include("brisk.jl") +include("censure.jl") -export Keypoint, Keypoints, Feature, Features, Params, BRIEF, ORB, FREAK, BRISK +export Keypoint, Keypoints, BRIEF, DescriptorParams, ORB, CENSURE, OctagonFilter, BoxFilter, BiFilter, Detector export #Core @@ -56,5 +56,8 @@ export random_coarse, gaussian, gaussian_local, - centered + centered, + + #CENSURE + censure end diff --git a/src/censure.jl b/src/censure.jl new file mode 100644 index 0000000..c2ef13d --- /dev/null +++ b/src/censure.jl @@ -0,0 +1,65 @@ +abstract BiFilter + +type BoxFilter <: BiFilter + + filter :: Array{Float64, 2} + m_out :: UInt8 + m_in :: UInt8 + + BoxFilter(mo, mi) = new(ones(Float64, mo, mo), mo, mi) + +end + +type OctagonFilter <: BiFilter + + filter :: Array{Float64, 2} + m_out :: UInt8 + m_in :: UInt8 + n_out :: UInt8 + n_in :: UInt8 + + OctagonFilter(mo, mi, no, ni) = new(ones(Float64, mo + 2 * no, mo + 2 * no), mo, mi, no, ni) + +end + +type CENSURE <: Detector + + smallest :: Integer + largest :: Integer + filter :: Type + responseThreshold :: Number + lineThreshold :: Number + +end + +function createFilter(OF::OctagonFilter) + inner_start = Int(0.5 * ((OF.m_out + 2 * OF.n_out) - (OF.m_in + 2 * OF.n_in))) + OF.filter[inner_start + 1 : end - inner_start, inner_start + 1 : end - inner_start] = -1 + + for i in 1:OF.n_in + OF.filter[inner_start + i, inner_start + 1 : inner_start + OF.n_in - i + 1] = 0 + OF.filter[inner_start + i, inner_start + OF.n_in + OF.m_in + i : inner_start + OF.m_in + 2 * OF.n_in] = 0 + OF.filter[inner_start + OF.m_in + 2 * OF.n_in - i + 1, inner_start + 1 : inner_start + OF.n_in - i + 1] = 0 + OF.filter[inner_start + OF.m_in + 2 * OF.n_in - i + 1, inner_start + OF.n_in + OF.m_in + i : inner_start + OF.m_in + 2 * OF.n_in] = 0 + end + + for i in 1:OF.n_out + OF.filter[i, 1 : OF.n_out - i + 1] = 0 + OF.filter[i, OF.n_out + OF.m_out + i : OF.m_out + 2 * OF.n_out] = 0 + OF.filter[OF.m_out + 2 * OF.n_out - i + 1, 1 : OF.n_out - i + 1] = 0 + OF.filter[OF.m_out + 2 * OF.n_out - i + 1, OF.n_out + OF.m_out + i : OF.m_out + 2 * OF.n_out] = 0 + end + +end + +function createFilter(BF::BoxFilter) + inner_start = Int(0.5 * (BF.m_out - BF.m_in)) + BF.filter[inner_start + 1 : end - inner_start, inner_start + 1 : end - inner_start] = -1 +end + +CENSURE(; smallest::Integer = 1, largest::Integer = 7, filter::Type = BoxFilter, responseThreshold::Number = 0.15, lineThreshold::Number = 10) = CENSURE(scale, filter, responseThreshold, lineThreshold) + +function censure{T}(img::AbstractArray{T, 2}, params::CENSURE) + + +end \ No newline at end of file From 22eae1366b92145bc079adf06aa76188c596f1be Mon Sep 17 00:00:00 2001 From: mronian Date: Fri, 1 Jul 2016 09:47:56 +0530 Subject: [PATCH 2/7] Adds Filter Stack for OctagonalFilter --- src/censure.jl | 53 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/censure.jl b/src/censure.jl index c2ef13d..dd3dc02 100644 --- a/src/censure.jl +++ b/src/censure.jl @@ -3,10 +3,7 @@ abstract BiFilter type BoxFilter <: BiFilter filter :: Array{Float64, 2} - m_out :: UInt8 - m_in :: UInt8 - - BoxFilter(mo, mi) = new(ones(Float64, mo, mo), mo, mi) + scale :: UInt8 end @@ -18,29 +15,33 @@ type OctagonFilter <: BiFilter n_out :: UInt8 n_in :: UInt8 - OctagonFilter(mo, mi, no, ni) = new(ones(Float64, mo + 2 * no, mo + 2 * no), mo, mi, no, ni) - end type CENSURE <: Detector smallest :: Integer largest :: Integer - filter :: Type + filter_type :: Type + filter_stack :: Array{BiFilter} responseThreshold :: Number lineThreshold :: Number end function createFilter(OF::OctagonFilter) + area_out = (OF.m_out + 2 * OF.n_out) ^ 2 - 2 * OF.n_out ^ 2 + area_in = (OF.m_in + 2 * OF.n_in) ^ 2 - 2 * OF.n_in ^ 2 + weight_out = 1.0/(area_out - area_in) + weight_in = 1.0/area_in + OF.filter[:, :] = weight_out inner_start = Int(0.5 * ((OF.m_out + 2 * OF.n_out) - (OF.m_in + 2 * OF.n_in))) - OF.filter[inner_start + 1 : end - inner_start, inner_start + 1 : end - inner_start] = -1 + OF.filter[inner_start + 1 : end - inner_start, inner_start + 1 : end - inner_start] = weight_in for i in 1:OF.n_in - OF.filter[inner_start + i, inner_start + 1 : inner_start + OF.n_in - i + 1] = 0 - OF.filter[inner_start + i, inner_start + OF.n_in + OF.m_in + i : inner_start + OF.m_in + 2 * OF.n_in] = 0 - OF.filter[inner_start + OF.m_in + 2 * OF.n_in - i + 1, inner_start + 1 : inner_start + OF.n_in - i + 1] = 0 - OF.filter[inner_start + OF.m_in + 2 * OF.n_in - i + 1, inner_start + OF.n_in + OF.m_in + i : inner_start + OF.m_in + 2 * OF.n_in] = 0 + OF.filter[inner_start + i, inner_start + 1 : inner_start + OF.n_in - i + 1] = weight_out + OF.filter[inner_start + i, inner_start + OF.n_in + OF.m_in + i : inner_start + OF.m_in + 2 * OF.n_in] = weight_out + OF.filter[inner_start + OF.m_in + 2 * OF.n_in - i + 1, inner_start + 1 : inner_start + OF.n_in - i + 1] = weight_out + OF.filter[inner_start + OF.m_in + 2 * OF.n_in - i + 1, inner_start + OF.n_in + OF.m_in + i : inner_start + OF.m_in + 2 * OF.n_in] = weight_out end for i in 1:OF.n_out @@ -53,13 +54,33 @@ function createFilter(OF::OctagonFilter) end function createFilter(BF::BoxFilter) - inner_start = Int(0.5 * (BF.m_out - BF.m_in)) - BF.filter[inner_start + 1 : end - inner_start, inner_start + 1 : end - inner_start] = -1 + end -CENSURE(; smallest::Integer = 1, largest::Integer = 7, filter::Type = BoxFilter, responseThreshold::Number = 0.15, lineThreshold::Number = 10) = CENSURE(scale, filter, responseThreshold, lineThreshold) +OctagonFilter(mo, mi, no, ni) = (OF = OctagonFilter(ones(Float64, mo + 2 * no, mo + 2 * no), mo, mi, no, ni); createFilter(OF); OF) +BoxFilter(s) = (BF = BoxFilter(ones(Float64, 4 * s + 1, 4 * s + 1), s); createFilter(BF); BF) -function censure{T}(img::AbstractArray{T, 2}, params::CENSURE) +OctagonFilter_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] + ] +BoxFilter_Kernels = [1, 2, 3, 4, 5, 6, 7] +Kernels = Dict(BoxFilter => BoxFilter_Kernels, OctagonFilter => OctagonFilter_Kernels) + +function getFilterStack(filter_type::Type, smallest::Integer, largest::Integer) + k = Kernels[filter_type] + filter_stack = map(f -> filter_type(f...), k[smallest : largest]) +end + +CENSURE(; smallest::Integer = 1, largest::Integer = 7, filter::Type = OctagonFilter, responseThreshold::Number = 0.15, lineThreshold::Number = 10) = CENSURE(smallest, largest, filter, getFilterStack(filter, smallest, largest), responseThreshold, lineThreshold) + +function censure{T}(img::AbstractArray{T, 2}, params::CENSURE) + end \ No newline at end of file From 32027e9dad8921d7756c64955ea56b6e23cd12ff Mon Sep 17 00:00:00 2001 From: mronian Date: Sun, 3 Jul 2016 10:10:50 +0530 Subject: [PATCH 3/7] Adds FilterResponse for BoxFilter, Slant Integral Images for OctagonFilter --- src/censure.jl | 93 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 11 deletions(-) diff --git a/src/censure.jl b/src/censure.jl index dd3dc02..0ed97e0 100644 --- a/src/censure.jl +++ b/src/censure.jl @@ -1,9 +1,14 @@ abstract BiFilter type BoxFilter <: BiFilter - - filter :: Array{Float64, 2} - scale :: UInt8 + + scale :: Integer + in_length :: Integer + out_length :: Integer + in_area :: Float64 + out_area :: Float64 + in_weight :: Float64 + out_weight :: Float64 end @@ -22,7 +27,7 @@ type CENSURE <: Detector smallest :: Integer largest :: Integer filter_type :: Type - filter_stack :: Array{BiFilter} + filter_stack :: Array responseThreshold :: Number lineThreshold :: Number @@ -53,12 +58,8 @@ function createFilter(OF::OctagonFilter) end -function createFilter(BF::BoxFilter) - -end - OctagonFilter(mo, mi, no, ni) = (OF = OctagonFilter(ones(Float64, mo + 2 * no, mo + 2 * no), mo, mi, no, ni); createFilter(OF); OF) -BoxFilter(s) = (BF = BoxFilter(ones(Float64, 4 * s + 1, 4 * s + 1), s); createFilter(BF); BF) +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; ) OctagonFilter_Kernels = [ [5, 3, 2, 0], @@ -79,8 +80,78 @@ function getFilterStack(filter_type::Type, smallest::Integer, largest::Integer) filter_stack = map(f -> filter_type(f...), k[smallest : largest]) end -CENSURE(; smallest::Integer = 1, largest::Integer = 7, filter::Type = OctagonFilter, responseThreshold::Number = 0.15, lineThreshold::Number = 10) = CENSURE(smallest, largest, filter, getFilterStack(filter, smallest, largest), responseThreshold, lineThreshold) +function filterResponse{T}(int_img::AbstractArray{T, 2}, filter::BoxFilter) + margin = filter.scale * 2 + n = filter.scale + img_shape = size(int_img) + response = zeros(img_shape) + R = CartesianRange(CartesianIndex((margin + 1, margin + 1)), CartesianIndex((img_shape[1] - margin, img_shape[2] - margin))) + in_sum = 0.0 + out_sum = 0.0 + for I in R + topleft = I + CartesianIndex(- n - 1, - n - 1) + topright = I + CartesianIndex(n, - n - 1) + bottomleft = I + CartesianIndex(- n - 1, n) + bottomright = I + CartesianIndex(n, n) + A = topleft >= CartesianIndex(1, 1) ? int_img[topleft] : 0.0 + B = topright >= CartesianIndex(1, 1) ? int_img[topright] : 0.0 + C = bottomleft >= CartesianIndex(1, 1) ? int_img[bottomleft] : 0.0 + D = bottomright >= CartesianIndex(1, 1) ? int_img[bottomright] : 0.0 + in_sum = A + D - B - C + + topleft = I + CartesianIndex(- 2 * n - 1, - 2 * n - 1) + topright = I + CartesianIndex(2 * n, - 2 * n - 1) + bottomleft = I + CartesianIndex(- 2 * n - 1, 2 * n) + bottomright = I + CartesianIndex(2 * n, 2 * n) + A = topleft >= CartesianIndex(1, 1) ? int_img[topleft] : 0.0 + B = topright >= CartesianIndex(1, 1) ? int_img[topright] : 0.0 + C = bottomleft >= CartesianIndex(1, 1) ? int_img[bottomleft] : 0.0 + D = bottomright >= CartesianIndex(1, 1) ? int_img[bottomright] : 0.0 + out_sum = A + D - B - C - in_sum + + response[I] = in_sum * filter.in_weight - out_sum * filer.out_weight + end + + response +end + +function filterResponse(int_imgs::Tuple, filter::OctagonFilter) + int_img = int_imgs[1] + rs_img = int_imgs[2] + ls_img = int_imgs[3] +end + +getIntegralImage(img, filter_type::BoxFilter) = integral_image(img) + +function getIntegralImage(img, filter_type::OctagonFilter) + 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 + +CENSURE(; smallest::Integer = 1, largest::Integer = 7, filter::Type = BoxFilter, responseThreshold::Number = 0.15, lineThreshold::Number = 10) = CENSURE(smallest, largest, filter, getFilterStack(filter, smallest, largest), responseThreshold, lineThreshold) function censure{T}(img::AbstractArray{T, 2}, params::CENSURE) - + int_img = getIntegralImage(img, params.filter_stack[1]) + responses = map(f -> filterResponse(int_img, f), params.filter_stack) + responses end \ No newline at end of file From a9646b65b22e8dacc6bbcedf1f3fb1dbd79a6b2a Mon Sep 17 00:00:00 2001 From: mronian Date: Sun, 3 Jul 2016 16:51:17 +0530 Subject: [PATCH 4/7] Adds FilterResponse for OctagonFilter --- src/censure.jl | 190 +++++++++++++++++++++++++++++++---------------- test/runtests.jl | 1 + 2 files changed, 129 insertions(+), 62 deletions(-) diff --git a/src/censure.jl b/src/censure.jl index 0ed97e0..3f83a84 100644 --- a/src/censure.jl +++ b/src/censure.jl @@ -14,11 +14,14 @@ end type OctagonFilter <: BiFilter - filter :: Array{Float64, 2} - m_out :: UInt8 - m_in :: UInt8 - n_out :: UInt8 - n_in :: UInt8 + m_out :: Integer + m_in :: Integer + n_out :: Integer + n_in :: Integer + in_area :: Float64 + out_area :: Float64 + in_weight :: Float64 + out_weight :: Float64 end @@ -33,33 +36,21 @@ type CENSURE <: Detector end -function createFilter(OF::OctagonFilter) - area_out = (OF.m_out + 2 * OF.n_out) ^ 2 - 2 * OF.n_out ^ 2 - area_in = (OF.m_in + 2 * OF.n_in) ^ 2 - 2 * OF.n_in ^ 2 - weight_out = 1.0/(area_out - area_in) - weight_in = 1.0/area_in - OF.filter[:, :] = weight_out - inner_start = Int(0.5 * ((OF.m_out + 2 * OF.n_out) - (OF.m_in + 2 * OF.n_in))) - OF.filter[inner_start + 1 : end - inner_start, inner_start + 1 : end - inner_start] = weight_in - - for i in 1:OF.n_in - OF.filter[inner_start + i, inner_start + 1 : inner_start + OF.n_in - i + 1] = weight_out - OF.filter[inner_start + i, inner_start + OF.n_in + OF.m_in + i : inner_start + OF.m_in + 2 * OF.n_in] = weight_out - OF.filter[inner_start + OF.m_in + 2 * OF.n_in - i + 1, inner_start + 1 : inner_start + OF.n_in - i + 1] = weight_out - OF.filter[inner_start + OF.m_in + 2 * OF.n_in - i + 1, inner_start + OF.n_in + OF.m_in + i : inner_start + OF.m_in + 2 * OF.n_in] = weight_out - end - - for i in 1:OF.n_out - OF.filter[i, 1 : OF.n_out - i + 1] = 0 - OF.filter[i, OF.n_out + OF.m_out + i : OF.m_out + 2 * OF.n_out] = 0 - OF.filter[OF.m_out + 2 * OF.n_out - i + 1, 1 : OF.n_out - i + 1] = 0 - OF.filter[OF.m_out + 2 * OF.n_out - i + 1, OF.n_out + OF.m_out + i : OF.m_out + 2 * OF.n_out] = 0 - 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 -OctagonFilter(mo, mi, no, ni) = (OF = OctagonFilter(ones(Float64, mo + 2 * no, mo + 2 * no), mo, mi, no, ni); createFilter(OF); OF) -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; ) +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 OctagonFilter_Kernels = [ [5, 3, 2, 0], @@ -80,9 +71,36 @@ function getFilterStack(filter_type::Type, smallest::Integer, largest::Integer) filter_stack = map(f -> filter_type(f...), k[smallest : largest]) end -function filterResponse{T}(int_img::AbstractArray{T, 2}, filter::BoxFilter) - margin = filter.scale * 2 - n = filter.scale +getIntegralImage(img, filter_type::BoxFilter) = integral_image(img) + +function getIntegralImage(img, filter_type::OctagonFilter) + 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 filterResponse{T}(int_img::AbstractArray{T, 2}, BF::BoxFilter) + margin = BF.scale * 2 + n = BF.scale img_shape = size(int_img) response = zeros(img_shape) R = CartesianRange(CartesianIndex((margin + 1, margin + 1)), CartesianIndex((img_shape[1] - margin, img_shape[2] - margin))) @@ -90,8 +108,8 @@ function filterResponse{T}(int_img::AbstractArray{T, 2}, filter::BoxFilter) out_sum = 0.0 for I in R topleft = I + CartesianIndex(- n - 1, - n - 1) - topright = I + CartesianIndex(n, - n - 1) - bottomleft = I + CartesianIndex(- n - 1, n) + topright = I + CartesianIndex(- n - 1, n) + bottomleft = I + CartesianIndex(n, - n - 1) bottomright = I + CartesianIndex(n, n) A = topleft >= CartesianIndex(1, 1) ? int_img[topleft] : 0.0 B = topright >= CartesianIndex(1, 1) ? int_img[topright] : 0.0 @@ -100,8 +118,8 @@ function filterResponse{T}(int_img::AbstractArray{T, 2}, filter::BoxFilter) in_sum = A + D - B - C topleft = I + CartesianIndex(- 2 * n - 1, - 2 * n - 1) - topright = I + CartesianIndex(2 * n, - 2 * n - 1) - bottomleft = I + CartesianIndex(- 2 * n - 1, 2 * n) + topright = I + CartesianIndex(- 2 * n - 1, 2 * n) + bottomleft = I + CartesianIndex(2 * n, - 2 * n - 1) bottomright = I + CartesianIndex(2 * n, 2 * n) A = topleft >= CartesianIndex(1, 1) ? int_img[topleft] : 0.0 B = topright >= CartesianIndex(1, 1) ? int_img[topright] : 0.0 @@ -109,43 +127,91 @@ function filterResponse{T}(int_img::AbstractArray{T, 2}, filter::BoxFilter) D = bottomright >= CartesianIndex(1, 1) ? int_img[bottomright] : 0.0 out_sum = A + D - B - C - in_sum - response[I] = in_sum * filter.in_weight - out_sum * filer.out_weight + response[I] = in_sum * BF.in_weight - out_sum * BF.out_weight end response end -function filterResponse(int_imgs::Tuple, filter::OctagonFilter) +function filterResponse(int_imgs::Tuple, OF::OctagonFilter) int_img = int_imgs[1] rs_img = int_imgs[2] ls_img = int_imgs[3] -end -getIntegralImage(img, filter_type::BoxFilter) = integral_image(img) - -function getIntegralImage(img, filter_type::OctagonFilter) - img_shape = size(img) - int_img = zeros(img_shape) - right_slant_img = zeros(img_shape) - left_slant_img = zeros(img_shape) + 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)) - int_img[1, :] = cumsum(img[1, :]) - right_slant_img[1, :] = int_img[1, :] - left_slant_img[1, :] = int_img[1, :] + img_shape = size(int_img) + response = zeros(img_shape) + R = CartesianRange(CartesianIndex((margin + 1, margin + 1)), 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, - m_in2 - OF.n_in - 1) + bottomleft = I + CartesianIndex(- m_in2 - 1, m_in2 + OF.n_in) + bottomright = I + CartesianIndex(m_in2, m_in2 + OF.n_in) + A = topleft >= CartesianIndex(1, 1) ? int_img[topleft] : 0.0 + B = topright >= CartesianIndex(1, 1) ? int_img[topright] : 0.0 + C = bottomleft >= CartesianIndex(1, 1) ? int_img[bottomleft] : 0.0 + D = bottomright >= CartesianIndex(1, 1) ? int_img[bottomright] : 0.0 + in_sum = A + D - B - C - 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 + 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 = trap_top_left >= CartesianIndex(1, 1) ? ls_img[trap_top_left] : 0.0 + B = trap_top_right >= CartesianIndex(1, 1) ? rs_img[trap_top_right] : 0.0 + C = trap_bot_left >= CartesianIndex(1, 1) ? ls_img[trap_bot_left] : 0.0 + D = trap_bot_right >= CartesianIndex(1, 1) ? rs_img[trap_bot_right] : 0.0 + 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 = trap_top_left >= CartesianIndex(1, 1) ? rs_img[trap_top_left] : 0.0 + B = trap_top_right >= CartesianIndex(1, 1) ? ls_img[trap_top_right] : 0.0 + C = trap_bot_left >= CartesianIndex(1, 1) ? rs_img[trap_bot_left] : 0.0 + D = trap_bot_right >= CartesianIndex(1, 1) ? ls_img[trap_bot_right] : 0.0 + 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 = topleft >= CartesianIndex(1, 1) ? int_img[topleft] : 0.0 + B = topright >= CartesianIndex(1, 1) ? int_img[topright] : 0.0 + C = bottomleft >= CartesianIndex(1, 1) ? int_img[bottomleft] : 0.0 + D = bottomright >= CartesianIndex(1, 1) ? int_img[bottomright] : 0.0 + 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 = trap_top_left >= CartesianIndex(1, 1) ? ls_img[trap_top_left] : 0.0 + B = trap_top_right >= CartesianIndex(1, 1) ? rs_img[trap_top_right] : 0.0 + C = trap_bot_left >= CartesianIndex(1, 1) ? ls_img[trap_bot_left] : 0.0 + D = trap_bot_right >= CartesianIndex(1, 1) ? rs_img[trap_bot_right] : 0.0 + 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 = trap_top_left >= CartesianIndex(1, 1) ? rs_img[trap_top_left] : 0.0 + B = trap_top_right >= CartesianIndex(1, 1) ? ls_img[trap_top_right] : 0.0 + C = trap_bot_left >= CartesianIndex(1, 1) ? rs_img[trap_bot_left] : 0.0 + D = trap_bot_right >= CartesianIndex(1, 1) ? ls_img[trap_bot_right] : 0.0 + out_sum += A + D - B - C + out_sum = out_sum - in_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 + response[I] = in_sum * filter.in_weight - out_sum * filer.out_weight + end + response + end CENSURE(; smallest::Integer = 1, largest::Integer = 7, filter::Type = BoxFilter, responseThreshold::Number = 0.15, lineThreshold::Number = 10) = CENSURE(smallest, largest, filter, getFilterStack(filter, smallest, largest), responseThreshold, lineThreshold) diff --git a/test/runtests.jl b/test/runtests.jl index 643fc42..b7be5f6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -55,6 +55,7 @@ include("corner.jl") include("orb.jl") include("freak.jl") include("brisk.jl") +include("censure.jl") isinteractive() || FactCheck.exitstatus() From b1071ef8d005d645c91b22287ba36d71e46485a7 Mon Sep 17 00:00:00 2001 From: mronian Date: Mon, 4 Jul 2016 22:29:16 +0530 Subject: [PATCH 5/7] Adds Feature Detection. Harris Suppression Left --- src/censure.jl | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/censure.jl b/src/censure.jl index 3f83a84..5ca4c68 100644 --- a/src/censure.jl +++ b/src/censure.jl @@ -214,10 +214,23 @@ function filterResponse(int_imgs::Tuple, OF::OctagonFilter) end +function checkFeature() +end + CENSURE(; smallest::Integer = 1, largest::Integer = 7, filter::Type = BoxFilter, responseThreshold::Number = 0.15, lineThreshold::Number = 10) = CENSURE(smallest, largest, filter, getFilterStack(filter, smallest, largest), responseThreshold, lineThreshold) function censure{T}(img::AbstractArray{T, 2}, params::CENSURE) int_img = getIntegralImage(img, params.filter_stack[1]) responses = map(f -> filterResponse(int_img, f), params.filter_stack) - responses + # minima, maxima = extrema_filter(padarray(responses, [1, 1, 1], [1, 1, 1], "replicate"), Array(3, 3, 3)) + # features = map(i -> (minima[i] == responses[i] || maxima[i] == responses[i]) && ( responses[i] > params.responseThreshold ), CartesianRange(size(responses))) + features = map(i -> checkFeature(), responses) + keypoints = Array{Keypoints}([]) + 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 From 4d9c2d4e24e8795d03f011116249485eb8c0481f Mon Sep 17 00:00:00 2001 From: mronian Date: Thu, 28 Jul 2016 05:17:46 +0530 Subject: [PATCH 6/7] Adds tests for Filters, Integral Image, Responses --- test/censure.jl | 109 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 test/censure.jl diff --git a/test/censure.jl b/test/censure.jl new file mode 100644 index 0000000..21dabd2 --- /dev/null +++ b/test/censure.jl @@ -0,0 +1,109 @@ +using FactCheck, Base.Test, Images, Colors, FixedPointNumbers, ImageFeatures + +facts("CENSURE") do + + context("Filters") do + + bf = BoxFilter(1) + @fact bf.scale --> 1 + @fact bf.in_length --> 3 + @fact bf.out_length --> 5 + @fact bf.in_area --> 9.0 + @fact bf.out_area --> 25.0 + @fact isapprox(bf.in_weight, 1 / 9) --> true + @fact isapprox(bf.out_weight, 1 / 16) --> true + bf = BoxFilter(5) + @fact bf.scale --> 5 + @fact bf.in_length --> 11 + @fact bf.out_length --> 21 + @fact bf.in_area --> 121.0 + @fact bf.out_area --> 441.0 + @fact isapprox(bf.in_weight, 1 / 121) --> true + @fact isapprox(bf.out_weight, 1 / 320) --> true + + of = OctagonFilter(5, 3, 2, 0) + @fact of.m_out --> 5 + @fact of.m_in --> 3 + @fact of.n_out --> 2 + @fact of.n_in --> 0 + @fact of.in_area --> 9.0 + @fact of.out_area --> 73.0 + @fact isapprox(of.in_weight, 1 / 9) --> true + @fact isapprox(of.out_weight, 1 / 64) --> true + + of = OctagonFilter(13, 5, 7, 4) + @fact of.m_out --> 13 + @fact of.m_in --> 5 + @fact of.n_out --> 7 + @fact of.n_in --> 4 + @fact of.in_area --> 137.0 + @fact of.out_area --> 631.0 + @fact isapprox(of.in_weight, 1 / 137) --> true + @fact isapprox(of.out_weight, 1 / 494) --> true + + end + + context("Integral Image") do + + img = ones(5, 5) + bf = BoxFilter(1) + @fact 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) + @fact 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 ] + @fact 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 ] + @fact all(ls .== l_check) --> true + + end + + context("Filter Response") do + + 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) + @fact isapprox(response[4, 4], -0.895833, rtol = 0.001) --> true + @fact isapprox(response[4, 5], 0.888889, rtol = 0.001) --> true + @fact isapprox(response[5, 4], -0.958333, rtol = 0.001) --> true + @fact isapprox(response[5, 5], 0.604167, rtol = 0.001) --> true + @fact all(response[:, 1:3] .== 0) --> true + @fact all(response[1:3, :] .== 0) --> true + @fact all(response[:, 6:6] .== 0) --> true + @fact 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) + @fact isapprox(response[4, 4], -0.93056, rtol = 0.001) --> true + @fact isapprox(response[4, 5], -0.02777, rtol = 0.001) --> true + @fact isapprox(response[5, 4], -0.69444, rtol = 0.001) --> true + @fact isapprox(response[5, 5], 1.35417, rtol = 0.001) --> true + @fact all(response[:, 1:3] .== 0) --> true + @fact all(response[1:3, :] .== 0) --> true + @fact all(response[:, 6:6] .== 0) --> true + @fact all(response[6:7, :] .== 0) --> true + + end + +end \ No newline at end of file From 8c50f3918aafee41a8e0b5ab86f9b2f7adf795ef Mon Sep 17 00:00:00 2001 From: mronian Date: Thu, 28 Jul 2016 06:22:46 +0530 Subject: [PATCH 7/7] Working CENSURE --- REQUIRE | 3 - src/censure.jl | 382 +++++++++++++++++++++++++----------------------- test/censure.jl | 1 + 3 files changed, 197 insertions(+), 189 deletions(-) diff --git a/REQUIRE b/REQUIRE index 80a6fdd..1abc461 100644 --- a/REQUIRE +++ b/REQUIRE @@ -3,6 +3,3 @@ Images 0.5 Colors 0.6 ColorVectorSpace 0.1 FixedPointNumbers 0.1 -FileIO -Compat 0.7.15 -StatsBase diff --git a/src/censure.jl b/src/censure.jl index 5ca4c68..6e0fd7f 100644 --- a/src/censure.jl +++ b/src/censure.jl @@ -2,234 +2,244 @@ abstract BiFilter type BoxFilter <: BiFilter - scale :: Integer - in_length :: Integer - out_length :: Integer - in_area :: Float64 - out_area :: Float64 - in_weight :: Float64 - out_weight :: Float64 + 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 :: Integer - m_in :: Integer - n_out :: Integer - n_in :: Integer - in_area :: Float64 - out_area :: Float64 - in_weight :: Float64 - out_weight :: Float64 + + 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 CENSURE <: Detector +type CENSURE{F} <: Detector - smallest :: Integer - largest :: Integer - filter_type :: Type - filter_stack :: Array - responseThreshold :: Number - lineThreshold :: Number + 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 + 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 + 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 -OctagonFilter_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 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]] -BoxFilter_Kernels = [1, 2, 3, 4, 5, 6, 7] +const box_filter_kernels = [1, 2, 3, 4, 5, 6, 7] -Kernels = Dict(BoxFilter => BoxFilter_Kernels, OctagonFilter => OctagonFilter_Kernels) +_getkernel(::Type{BoxFilter}) = box_filter_kernels +_getkernel(::Type{OctagonFilter}) = octagon_filter_kernels -function getFilterStack(filter_type::Type, smallest::Integer, largest::Integer) - k = Kernels[filter_type] - filter_stack = map(f -> filter_type(f...), k[smallest : largest]) +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 -getIntegralImage(img, filter_type::BoxFilter) = integral_image(img) - -function getIntegralImage(img, filter_type::OctagonFilter) - 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 +_get_integral_image(img, filter_type::BoxFilter) = integral_image(img) + +function _get_integral_image(img, filter_type::OctagonFilter) + 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 filterResponse{T}(int_img::AbstractArray{T, 2}, BF::BoxFilter) - margin = BF.scale * 2 - n = BF.scale - img_shape = size(int_img) - response = zeros(img_shape) - R = CartesianRange(CartesianIndex((margin + 1, margin + 1)), CartesianIndex((img_shape[1] - margin, img_shape[2] - margin))) - in_sum = 0.0 - out_sum = 0.0 +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 = topleft >= CartesianIndex(1, 1) ? int_img[topleft] : 0.0 - B = topright >= CartesianIndex(1, 1) ? int_img[topright] : 0.0 - C = bottomleft >= CartesianIndex(1, 1) ? int_img[bottomleft] : 0.0 - D = bottomright >= CartesianIndex(1, 1) ? int_img[bottomright] : 0.0 - 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 = topleft >= CartesianIndex(1, 1) ? int_img[topleft] : 0.0 - B = topright >= CartesianIndex(1, 1) ? int_img[topright] : 0.0 - C = bottomleft >= CartesianIndex(1, 1) ? int_img[bottomleft] : 0.0 - D = bottomright >= CartesianIndex(1, 1) ? int_img[bottomright] : 0.0 - out_sum = A + D - B - C - in_sum - - response[I] = in_sum * BF.in_weight - out_sum * BF.out_weight + 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 filterResponse(int_imgs::Tuple, OF::OctagonFilter) - int_img = int_imgs[1] - rs_img = int_imgs[2] - ls_img = int_imgs[3] +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)) + 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(img_shape) - R = CartesianRange(CartesianIndex((margin + 1, margin + 1)), CartesianIndex((img_shape[1] - margin, img_shape[2] - margin))) + 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, - m_in2 - OF.n_in - 1) - bottomleft = I + CartesianIndex(- m_in2 - 1, m_in2 + OF.n_in) - bottomright = I + CartesianIndex(m_in2, m_in2 + OF.n_in) - A = topleft >= CartesianIndex(1, 1) ? int_img[topleft] : 0.0 - B = topright >= CartesianIndex(1, 1) ? int_img[topright] : 0.0 - C = bottomleft >= CartesianIndex(1, 1) ? int_img[bottomleft] : 0.0 - D = bottomright >= CartesianIndex(1, 1) ? int_img[bottomright] : 0.0 - 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 = trap_top_left >= CartesianIndex(1, 1) ? ls_img[trap_top_left] : 0.0 - B = trap_top_right >= CartesianIndex(1, 1) ? rs_img[trap_top_right] : 0.0 - C = trap_bot_left >= CartesianIndex(1, 1) ? ls_img[trap_bot_left] : 0.0 - D = trap_bot_right >= CartesianIndex(1, 1) ? rs_img[trap_bot_right] : 0.0 - 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 = trap_top_left >= CartesianIndex(1, 1) ? rs_img[trap_top_left] : 0.0 - B = trap_top_right >= CartesianIndex(1, 1) ? ls_img[trap_top_right] : 0.0 - C = trap_bot_left >= CartesianIndex(1, 1) ? rs_img[trap_bot_left] : 0.0 - D = trap_bot_right >= CartesianIndex(1, 1) ? ls_img[trap_bot_right] : 0.0 - 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 = topleft >= CartesianIndex(1, 1) ? int_img[topleft] : 0.0 - B = topright >= CartesianIndex(1, 1) ? int_img[topright] : 0.0 - C = bottomleft >= CartesianIndex(1, 1) ? int_img[bottomleft] : 0.0 - D = bottomright >= CartesianIndex(1, 1) ? int_img[bottomright] : 0.0 - 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 = trap_top_left >= CartesianIndex(1, 1) ? ls_img[trap_top_left] : 0.0 - B = trap_top_right >= CartesianIndex(1, 1) ? rs_img[trap_top_right] : 0.0 - C = trap_bot_left >= CartesianIndex(1, 1) ? ls_img[trap_bot_left] : 0.0 - D = trap_bot_right >= CartesianIndex(1, 1) ? rs_img[trap_bot_right] : 0.0 - 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 = trap_top_left >= CartesianIndex(1, 1) ? rs_img[trap_top_left] : 0.0 - B = trap_top_right >= CartesianIndex(1, 1) ? ls_img[trap_top_right] : 0.0 - C = trap_bot_left >= CartesianIndex(1, 1) ? rs_img[trap_bot_left] : 0.0 - D = trap_bot_right >= CartesianIndex(1, 1) ? ls_img[trap_bot_right] : 0.0 - out_sum += A + D - B - C - out_sum = out_sum - in_sum - - response[I] = in_sum * filter.in_weight - out_sum * filer.out_weight + topleft = I + CartesianIndex(- m_in2 - 1, - m_in2 - OF.n_in - 1) + topright = I + CartesianIndex(m_in2, - m_in2 - OF.n_in - 1) + bottomleft = I + CartesianIndex(- m_in2 - 1, m_in2 + OF.n_in) + 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 - + response + end -function checkFeature() +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 -CENSURE(; smallest::Integer = 1, largest::Integer = 7, filter::Type = BoxFilter, responseThreshold::Number = 0.15, lineThreshold::Number = 10) = CENSURE(smallest, largest, filter, getFilterStack(filter, smallest, largest), responseThreshold, lineThreshold) - -function censure{T}(img::AbstractArray{T, 2}, params::CENSURE) - int_img = getIntegralImage(img, params.filter_stack[1]) - responses = map(f -> filterResponse(int_img, f), params.filter_stack) - # minima, maxima = extrema_filter(padarray(responses, [1, 1, 1], [1, 1, 1], "replicate"), Array(3, 3, 3)) - # features = map(i -> (minima[i] == responses[i] || maxima[i] == responses[i]) && ( responses[i] > params.responseThreshold ), CartesianRange(size(responses))) - features = map(i -> checkFeature(), responses) - keypoints = Array{Keypoints}([]) +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!(keypoints, map((r, c) -> Keypoint(r, c), rows, cols)) append!(scales, ones(length(rows)) * scale) end keypoints, scales diff --git a/test/censure.jl b/test/censure.jl index 21dabd2..09c0e94 100644 --- a/test/censure.jl +++ b/test/censure.jl @@ -104,6 +104,7 @@ facts("CENSURE") do @fact all(response[:, 6:6] .== 0) --> true @fact all(response[6:7, :] .== 0) --> true + end end \ No newline at end of file