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

[WIP]Add boosting tracker #20

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
21 changes: 0 additions & 21 deletions Manifest.toml

This file was deleted.

28 changes: 28 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,30 @@
name = "ImageTracking"
uuid = "5cb2747a-620a-11e9-38cd-3dc946e3e5f7"
version = "0.1.0"

[deps]
AxisAlgorithms = "13072b0f-2c55-5437-9ae7-d433b7a33950"
CoordinateTransformations = "150eb455-5306-5404-9cee-2592286d6298"
ImageFiltering = "6a3955dd-da59-5b1f-98d4-e7296123deb5"
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[compat]
AxisAlgorithms = ">= 0.2"
ImageFiltering = ">= 0.3"
Images = ">= 0.17"
Interpolations = ">= 0.7"
julia = ">= 0.7"

[extras]
ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
QuartzImageIO = "dca85d43-d64c-5e67-8c65-017450d5d020"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990"

[targets]
test = ["Test", "TestImages", "ImageMagick", "QuartzImageIO"]
6 changes: 0 additions & 6 deletions REQUIRE

This file was deleted.

5 changes: 3 additions & 2 deletions src/ImageTracking.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ include("core.jl")
include("optical_flow.jl")
include("haar.jl")
include("utility.jl")
include("tracker.jl")
include("tracker/tracker.jl")

export

Expand Down Expand Up @@ -59,6 +59,7 @@ export

# tracking algorithms
BoxROI,
TrackerBoosting
TrackerBoosting,
init_tracker
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved

end
17 changes: 0 additions & 17 deletions src/boosting_tracker/boosting_tracker.jl

This file was deleted.

19 changes: 10 additions & 9 deletions src/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,23 @@ function pinv2x2(M::AbstractArray)
U*D*V'
end

mutable struct TrackerTargetState
abstract type AbstractTrackerTargetState end

mutable struct BoostingTrackerTargetState <: AbstractTrackerTargetState
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be kept in a separate file as well.

#Initialized
position::SVector{2, Float64}
height::Int
width::Int
height::Integer
width::Integer
Copy link
Member

Choose a reason for hiding this comment

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

I guess this stands for tracking region

position::SVector{2, Float64}
height::Integer
width::Integer

you can use Range to represent it as well.

is_target::Bool

#Uninitialized
responses::Array{T, 2} where T
Copy link
Member

Choose a reason for hiding this comment

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

What is the purpose of responses? If it is needed, then you should declare T as part of the struct, for example:
mutable struct BoostingTrackerTargetState{T <: AbstractArray} <: AbstractTrackerTargetState
responses::T
See: https://docs.julialang.org/en/v1/manual/performance-tips/index.html#Avoid-containers-with-abstract-type-parameters-1


TrackerTargetState(position::SVector{2, Float64}, height::Int, width::Int, is_target::Bool) = new(
position, height, width, is_target)
BoostingTrackerTargetState(position::SVector{2, Float64}, height::Integer, width::Integer, is_target::Bool) =
new(position, height, width, is_target)
end


mutable struct ConfidenceMap
states::Vector{TrackerTargetState}
confidence::Vector{Float64}
states::Vector{AbstractTrackerTargetState}
confidence::Vector{AbstractFloat}
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
end

29 changes: 29 additions & 0 deletions src/tracker/boosting_tracker.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#-----------------------------------
# Implementation of boosting tracker
#-----------------------------------

function init_tracker(tracker::TrackerBoosting, boxROI::BoxROI)
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
int_image = integral_image(boxROI.img)

# sampling
tracker.sampler = CurrentSample(tracker.sampler_overlap, tracker.sampler_search_factor, :positive)
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
int_box = BoxROI(int_image, boxROI.bound)
positive_samples = sample_tracker(tracker.sampler, int_box)

tracker.sampler.mode = :negative
negative_samples = sample_tracker(tracker.sampler, int_box)

if isempty(positive_samples) || isempty(negative_samples)
error("Couldn't get initial samples")
end

# compute harr haar_features

# model

# Run model estimation and update for initial iterations
end

function update_tracker(tracker::TrackerBoosting, image::AbstractArray)
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved

end
34 changes: 14 additions & 20 deletions src/tracker.jl → src/tracker/tracker.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
abstract type AbstractTracker end
#---------------------
# TRACKER COMPONENTS
#---------------------

abstract type AbstractROI end
mutable struct BoxROI{T <: AbstractArray, S <: AbstractArray} <: AbstractROI
img::T
bound::S
end
include("../core.jl")
include("tracker_sampler.jl")
# include("tracker_state_estimator.jl")
# include("tracker_model.jl")
# include("tracker_features.jl")

mutable struct TrackerBoosting{I <: Int, F <: Float64, B <: BoxROI} <: AbstractTracker
abstract type AbstractTracker end
mutable struct TrackerBoosting{I <: Integer, F <: AbstractFloat, B <: BoxROI} <: AbstractTracker
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
# initialized
boxROI::B
num_of_classifiers::I
Expand All @@ -15,10 +18,11 @@ mutable struct TrackerBoosting{I <: Int, F <: Float64, B <: BoxROI} <: AbstractT
initial_iterations::I
num_of_features::I

sampler::CurrentSample
# constructor
function TrackerBoosting{I, F, B}(box::B, num_of_classifiers::I = 100, sampler_overlap::F = 0.99,
sampler_search_factor::F = 1.8, initial_iterations::I = 20,
num_of_features::I = 1050)where {I <: Int, F <: Float64, B <: BoxROI}
num_of_features::I = 1050)where {I <: Integer, F <: AbstractFloat, B <: BoxROI}
if size(box.bound, 1) != 4
error("Invalid bounding box size")
end
Expand All @@ -42,28 +46,18 @@ mutable struct TrackerBoosting{I <: Int, F <: Float64, B <: BoxROI} <: AbstractT
if box.bound[2] > box.bound[4]
error("Invalid bounding box")
end

new(box, num_of_classifiers, sampler_overlap, sampler_search_factor, initial_iterations, num_of_features)
end
end
Copy link
Member

Choose a reason for hiding this comment

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

Note that in general you can write inequalities like this in Julia:

 if 0 < x < 1 
   do something
end

rather than

if x > 0 && x < 1
  do something
end

The former is much more readable.


TrackerBoosting(boxROI::B, num_of_classifiers::I, sampler_overlap::F, sampler_search_factor::F,
initial_iterations::I, num_of_features::I) where {I <: Int, F <: Float64, B <: BoxROI} =
initial_iterations::I, num_of_features::I) where {I <: Integer, F <: AbstractFloat, B <: BoxROI} =
TrackerBoosting{I, F, B}(boxROI, num_of_classifiers, sampler_overlap, sampler_search_factor,
initial_iterations, num_of_features)

#---------------------
# TRACKER COMPONENTS
#---------------------

include("core.jl")
# include("tracker_state_estimator.jl")
# include("tracker_model.jl")
# include("tracker_sampler.jl")
# include("tracker_features.jl")

#------------------
# IMPLEMENTATIONS
#------------------

include("boosting_tracker/boosting_tracker.jl")
include("boosting_tracker.jl")
98 changes: 98 additions & 0 deletions src/tracker/tracker_sampler.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
abstract type AbstractROI end
mutable struct BoxROI{T <: AbstractArray, S <: AbstractArray} <: AbstractROI
Copy link
Member

@johnnychen94 johnnychen94 Apr 20, 2019

Choose a reason for hiding this comment

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

mutable seems to be an overkill, and in julia we use Tuple for bound type, i.e., NTuple{4,Integer}.

Copy link
Member

Choose a reason for hiding this comment

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

I don't think we should be storing the entire image as a field in BoxROI. An abstract region of interest could just be a set of AbstractRange types, one for each dimensions. It would also not need to be mutable. You just instantiate a new when the ROI changes. I imagine something like this:

struct BoxROI{R₁ <: AbstractRange, R₂} <: AbstractROI
    span₁::R₁ 
    span₂::R₂
end

Copy link
Member

Choose a reason for hiding this comment

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

Is img used through the entire tracking life? If the answer is yes, we then have some reason to hold it in some struct( e.g., Tracker or BoxROI). If it's only used for initialization purpose, it's better not to do so.

img::T
bound::S
end

abstract type AbstractTrackerSampler end
mutable struct CurrentSample{F <: Float64, S <: Symbol} <: AbstractTrackerSampler
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
overlap::F
search_factor::F
mode::S
sampling_ROI::SVector{4, Integer}
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
valid_ROI::SVector{4, Integer}
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
tracked_patch::SVector{4, Integer}
CurrentSample{F, S}(overlap, search_factor, mode) where{F <: Float64, S <: Symbol} = new(overlap, search_factor, mode)
end

CurrentSample(overlap::F = 0.99, search_factor::F = 1.8, mode::S = :positive) where{F <: Float64, S <: Symbol} =
CurrentSample{F, S}(overlap, search_factor, mode)

function sample_tracker(sampler::CurrentSample, box::BoxROI)
sampler.tracked_patch = box.bound
sampler.valid_ROI = SVector{4, Integer}([1, 1, size(box.img, 1), size(box.img, 2)])
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved

height = box.bound[3] - box.bound[1] + 1
Copy link
Member

Choose a reason for hiding this comment

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

You can write a custom size(b::BoxROI) which returns the width and height as a tuple. Since the BoxROI consists of AbstractRange objects, this will be trivial.

width = box.bound[4] - box.bound[2] + 1

ROI_min_y = max(0, floor(Integer, box.bound[1] - height*((sampler.search_factor - 1) / 2) + 1))
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
ROI_min_x = max(0, floor(Integer, box.bound[2] - width*((sampler.search_factor - 1) / 2) + 1))

ROI_height = min(floor(Integer, height*sampler.search_factor), size(box.img, 1) - ROI_min_y + 1)
ROI_width = min(floor(Integer, width*sampler.search_factor), size(box.img, 2) - ROI_min_x + 1)

ROI_max_y = ROI_min_y + ROI_height - 1
ROI_max_x = ROI_min_x + ROI_width - 1

ROI = SVector{4, Integer}([ROI_min_y, ROI_min_x, ROI_max_y, ROI_max_x])

sample_pos_neg_roi(sampler, box, ROI)
end

function sample_pos_neg_roi(sampler::CurrentSample, box::BoxROI, ROI::SVector{4, Integer})
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
println(ROI)
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
println(sampler.valid_ROI)
if sampler.valid_ROI == ROI
sampler.sampling_ROI = ROI
else
sampler.sampling_ROI = SVector{4, Integer}(max(sampler.valid_ROI[1], ROI[1]), max(sampler.valid_ROI[2], ROI[2]),
min(sampler.valid_ROI[3], ROI[3]), min(sampler.valid_ROI[4], ROI[4]))
end

if sampler.mode == :positive
positive_sample = box.img[sampler.tracked_patch[1]:sampler.tracked_patch[3],
sampler.tracked_patch[2]:sampler.tracked_patch[4]]
positive_sample_pos = SVector{2, Integer}(sampler.tracked_patch[1], sampler.tracked_patch[2])
sample = fill((positive_sample, positive_sample_pos), (1, 4))
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
return sample
end

height = sampler.tracked_patch[3] - sampler.tracked_patch[1] + 1
width = sampler.tracked_patch[4] - sampler.tracked_patch[2] + 1

tl_block = SVector{4, Integer}(sampler.valid_ROI[1], sampler.valid_ROI[2], sampler.valid_ROI[1] + height - 1,
sampler.valid_ROI[2] + width - 1)
tr_block = SVector{4, Integer}(sampler.valid_ROI[1], sampler.valid_ROI[4] - width + 1, sampler.valid_ROI[1] + height - 1,
sampler.valid_ROI[4])
bl_block = SVector{4, Integer}(sampler.valid_ROI[3] - height + 1, sampler.valid_ROI[2], sampler.valid_ROI[3],
sampler.valid_ROI[2] + width - 1)
br_block = SVector{4, Integer}(sampler.valid_ROI[3] - height + 1, sampler.valid_ROI[4] - width + 1, sampler.valid_ROI[3],
sampler.valid_ROI[4])

if sampler.mode == :negative
tl_sample = box.img[tl_block[1]:tl_block[3], tl_block[2]:tl_block[4]]
tr_sample = box.img[tr_block[1]:tr_block[3], tr_block[2]:tr_block[4]]
bl_sample = box.img[bl_block[1]:bl_block[3], bl_block[2]:bl_block[4]]
br_sample = box.img[br_block[1]:br_block[3], br_block[2]:br_block[4]]
sample = [(tl_sample, SVector{2, Integer}(tl_block[1:2])), (tr_sample, SVector{2, Integer}(tr_block[1:2])),
(bl_sample, SVector{2, Integer}(bl_block[1:2])), (br_sample, SVector{2, Integer}(br_block[1:2]))]

return sample
end

step_row = max(1, floor(Int, (1 - sampler.overlap)*height + 0.5))
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
step_col = max(1, floor(Int, (1 - sampler.overlap)*width + 0.5))
max_row = sampler.sampling_ROI[3] - sampler.sampling_ROI[1] - height
max_col = sampler.sampling_ROI[4] - sampler.sampling_ROI[2] - width

sample = Array{Tuple{AbstractArray, SVector{2, Integer}}}
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
for i = 1:step_col:max_col
for j = 1:step_row:max_row
push!(sample, (box.img[j + sampler.sampling_ROI[1] - 1:j + sampler.sampling_ROI[1] + height - 2,
i + sampler.sampling_ROI[2] - 1:i + sampler.sampling_ROI[2] + width - 2],
SVector{2, Integer}(j + sampler.sampling_ROI[1]-1, i + sampler.sampling_ROI[2]-1)))
end
end

return sample
Deepank308 marked this conversation as resolved.
Show resolved Hide resolved
end
5 changes: 0 additions & 5 deletions test/REQUIRE

This file was deleted.