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

Dev #42

Merged
merged 2 commits into from
Oct 29, 2020
Merged

Dev #42

Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "FaceDetection"
uuid = "00808967-75e2-4046-a522-2ca211e35506"
authors = ["Jake W. Ireland <jakewilliami@icloud.com> and contributors"]
version = "0.2.0"
version = "1.0.0"

[deps]
ColorTypes = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
Expand Down
10 changes: 6 additions & 4 deletions examples/read.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Adapted from https://github.com/Simon-Hohberg/Viola-Jones/

println("\033[1;34m===>\033[0;38m\033[1;38m\tLoading required libraries (it will take a moment to precompile if it is your first time doing this)...\033[0;38m")

include(joinpath(dirname(dirname(@__FILE__)), "src", "FaceDetection.jl"))
include(joinpath(dirname(@__DIR__), "src", "FaceDetection.jl"))

using .FaceDetection
const FD = FaceDetection
Expand All @@ -33,14 +33,16 @@ function main(;

max_feature_width, max_feature_height, min_feature_height, min_feature_width, min_size_img = determine_feature_size(pos_testing_path, neg_testing_path; scale = scale, scale_to = scale_to)
img_size = scale ? scale_to : min_size_img
data_file = joinpath(dirname(@__FILE__), "data", "haar-like_features_c$(num_classifiers)_$(img_size)")
img_width, img_height = min_size_img
data_file = joinpath(@__DIR__, "data", "feature_votes_$(img_size)")

if ! isfile(data_file)
error(throw("You do not have a data file. Ensure you run \"write.jl\" to obtain your Haar-like features before running this script/"))
error(throw("You do not have a data file. Ensure you run \"write.jl\" to obtain your feature votes before running this programme."))
end

# read classifiers from file
classifiers = deserialize(data_file)
votes, features = deserialize(data_file)
classifiers = FD.learn(pos_training_path, neg_training_path, features, votes, num_classifiers)

FD.notify_user("Testing selected classifiers...")
num_faces = length(filtered_ls(pos_testing_path))
Expand Down
9 changes: 5 additions & 4 deletions examples/write.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Adapted from https://github.com/Simon-Hohberg/Viola-Jones/

println("\033[1;34m===>\033[0;38m\033[1;38m\tLoading required libraries (it will take a moment to precompile if it is your first time doing this)...\033[0;38m")

include(joinpath(dirname(dirname(@__FILE__)), "src", "FaceDetection.jl"))
include(joinpath(dirname(@__DIR__), "src", "FaceDetection.jl"))

using .FaceDetection
const FD = FaceDetection
Expand Down Expand Up @@ -45,12 +45,13 @@ function main(;
end

# classifiers are haar like features
classifiers = FD.learn(pos_training_path, neg_training_path, num_classifiers, min_feature_height, max_feature_height, min_feature_width, max_feature_width; scale = scale, scale_to = scale_to)
votes = FD.get_feature_votes(pos_training_path, neg_training_path, num_classifiers, min_feature_height, max_feature_height, min_feature_width, max_feature_width; scale = scale, scale_to = scale_to)


# write classifiers to file
img_size = scale ? scale_to : min_size_img
data_file = joinpath(dirname(@__FILE__), "data", "haar-like_features_c$(num_classifiers)_$(img_size)")
serialize(data_file, classifiers)
data_file = joinpath(@__DIR__, "data", "feature_votes_$(img_size)")
serialize(data_file, votes)
end

@time main(smart_choose_feats=true, scale=true, scale_to=(20, 20))
122 changes: 84 additions & 38 deletions src/AdaBoost.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,7 @@ using Base.Threads: @threads
using Base.Iterators: partition
using ProgressMeter: @showprogress, Progress, next!

#=
learn(
positive_iis::AbstractArray,
negative_iis::AbstractArray,
num_classifiers::Int64=-1,
min_feature_width::Int64=1,
max_feature_width::Int64=-1,
min_feature_height::Int64=1,
max_feature_height::Int64=-1
) ->::Array{HaarLikeObject,1}

The boosting algorithm for learning a query online. $T$ hypotheses are constructed, each using a single feature.
The final hypothesis is a weighted linear combination of the $T$ hypotheses, where the weights are inversely proportional to the training errors.
This function selects a set of classifiers. Iteratively takes the best classifiers based on a weighted error.

# Arguments

- `positive_iis::AbstractArray`: List of positive integral image examples
- `negative_iis::AbstractArray`: List of negative integral image examples
- `num_classifiers::Integer`: Number of classifiers to select. -1 will use all classifiers
- `min_feature_width::Integer`: the minimum width of the feature
- `max_feature_width::Integer`: the maximum width of the feature
- `min_feature_height::Integer`: the minimum height of the feature
- `max_feature_width::Integer`: the maximum height of the feature

# Returns `classifiers::Array{HaarLikeObject, 1}`: List of selected features
=#
function learn(
function get_feature_votes(
positive_path::AbstractString,
negative_path::AbstractString,
num_classifiers::Integer=-1,
Expand All @@ -53,7 +26,7 @@ function learn(
max_feature_height::Integer=-1;
scale::Bool = false,
scale_to::Tuple = (200, 200)
)::Array{HaarLikeObject,1}
)

# get number of positive and negative images (and create a global variable of the total number of images——global for the @everywhere scope)
positive_files = filtered_ls(positive_path)
Expand All @@ -73,18 +46,9 @@ function learn(
max_feature_height = isequal(max_feature_height, -1) ? img_height : max_feature_height
max_feature_width = isequal(max_feature_width, -1) ? img_height : max_feature_width

# Initialise weights $w_{1,i} = \frac{1}{2m}, \frac{1}{2l}$, for $y_i=0,1$ for negative and positive examples respectively
pos_weights = ones(num_pos) / (2 * num_pos)
neg_weights = ones(num_neg) / (2 * num_neg)

# Concatenate positive and negative weights into one `weights` array
weights = vcat(pos_weights, neg_weights)
labels = vcat(ones(Int8, num_pos), ones(Int8, num_neg) * -one(Int8))

# Create features for all sizes and locations
features = create_features(img_height, img_width, min_feature_width, max_feature_width, min_feature_height, max_feature_height)
num_features = length(features)
feature_indices = Array(1:num_features)
num_classifiers = isequal(num_classifiers, -1) ? num_features : num_classifiers

# create an empty array with dimensions (num_imgs, numFeautures)
Expand All @@ -106,6 +70,61 @@ function learn(
end
print("\n") # for a new line after the progress bar

return votes, features
end

#=
learn(
positive_iis::AbstractArray,
negative_iis::AbstractArray,
num_classifiers::Int64=-1,
min_feature_width::Int64=1,
max_feature_width::Int64=-1,
min_feature_height::Int64=1,
max_feature_height::Int64=-1
) ->::Array{HaarLikeObject,1}

The boosting algorithm for learning a query online. $T$ hypotheses are constructed, each using a single feature.
The final hypothesis is a weighted linear combination of the $T$ hypotheses, where the weights are inversely proportional to the training errors.
This function selects a set of classifiers. Iteratively takes the best classifiers based on a weighted error.

# Arguments

- `positive_iis::AbstractArray`: List of positive integral image examples
- `negative_iis::AbstractArray`: List of negative integral image examples
- `num_classifiers::Integer`: Number of classifiers to select. -1 will use all classifiers
- `min_feature_width::Integer`: the minimum width of the feature
- `max_feature_width::Integer`: the maximum width of the feature
- `min_feature_height::Integer`: the minimum height of the feature
- `max_feature_width::Integer`: the maximum height of the feature

# Returns `classifiers::Array{HaarLikeObject, 1}`: List of selected features
=#
function learn(
positive_path::AbstractString,
negative_path::AbstractString,
features::AbstractArray,
votes::AbstractArray,
num_classifiers::Integer=-1
)

# get number of positive and negative images (and create a global variable of the total number of images——global for the @everywhere scope)
num_pos = length(filtered_ls(positive_path))
num_neg = length(filtered_ls(negative_path))
num_imgs = num_pos + num_neg

# Initialise weights $w_{1,i} = \frac{1}{2m}, \frac{1}{2l}$, for $y_i=0,1$ for negative and positive examples respectively
pos_weights = ones(num_pos) / (2 * num_pos)
neg_weights = ones(num_neg) / (2 * num_neg)

# Concatenate positive and negative weights into one `weights` array
weights = vcat(pos_weights, neg_weights)
labels = vcat(ones(Int8, num_pos), ones(Int8, num_neg) * -one(Int8))

num_features = length(features)
feature_indices = Array(1:num_features)
num_classifiers = isequal(num_classifiers, -1) ? num_features : num_classifiers

notify_user("Selecting classifiers...")
# select classifiers
classifiers = []
Expand Down Expand Up @@ -145,6 +164,33 @@ function learn(
print("\n") # for a new line after the progress bar

return classifiers

end
function learn(
positive_path::AbstractString,
negative_path::AbstractString,
num_classifiers::Integer=-1,
min_feature_width::Integer=1,
max_feature_width::Integer=-1,
min_feature_height::Integer=1,
max_feature_height::Integer=-1;
scale::Bool = false,
scale_to::Tuple = (200, 200)
)::Array{HaarLikeObject,1}

votes, features = get_feature_votes(
positive_path,
negative_path,
num_classifiers,
min_feature_width,
max_feature_width,
min_feature_height,
max_feature_height,
scale = scale,
scale_to = scale_to
)

return learn(positive_path, negative_path, features, votes, num_classifiers)
end

#=
Expand Down