diff --git a/examples/alt_data.jl b/examples/alt_data.jl deleted file mode 100644 index e62fc6270..000000000 --- a/examples/alt_data.jl +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - #= - exec julia --project="$(realpath $(dirname $0))/" "${BASH_SOURCE[0]}" "$@" -e "include(popfirst!(ARGS))" \ - "${BASH_SOURCE[0]}" "$@" - =# - -pos_training_path = joinpath(alt_image_path, "pos") -neg_training_path = joinpath(alt_image_path, "neg") -# pos_testing_path = joinpath(alt_image_path, "testing", "pos") -# neg_testing_path = joinpath(homedir(), "Desktop", "Assorted Personal Documents", "Wallpapers copy") -pos_testing_path = joinpath(main_image_path, "testset", "faces")#joinpath(homedir(), "Desktop", "faces")#"$main_image_path/testset/faces/" -neg_testing_path = joinpath(main_image_path, "testset", "non-faces") - -# pos_training_path = joinpath(data_path, "lfw-all") -# neg_training_path = joinpath(data_path, "all-non-faces") -# pos_testing_path = joinpath(data_path, "lizzie-testset", "faces") -# neg_testing_path = joinpath(data_path, "lizzie-testset", "nonfaces") diff --git a/examples/basic.jl b/examples/basic.jl index cc9d541fb..603861dab 100755 --- a/examples/basic.jl +++ b/examples/basic.jl @@ -23,17 +23,11 @@ println("...done") function main(; smart_choose_feats::Bool=false, - alt::Bool=false, scale::Bool=false, scale_to::Tuple=(200, 200) ) - include("constants.jl") - - if ! alt - include("main_data.jl") - else - include("alt_data.jl") - end + include("constants.jl") + include("main_data.jl") min_size_img = (19, 19) # default for our test dataset if smart_choose_feats @@ -74,4 +68,4 @@ function main(; @printf("%10.9s %10.15s %15s\n\n", "Non-faces:", non_faces_frac, non_faces_percent) end -@time main(smart_choose_feats=true, alt=false, scale=true, scale_to=(19, 19)) +@time main(smart_choose_feats=true, scale=true, scale_to=(20, 20)) diff --git a/examples/constants.jl b/examples/constants.jl index 5853737ec..1667a7f75 100644 --- a/examples/constants.jl +++ b/examples/constants.jl @@ -11,5 +11,3 @@ main_image_path = joinpath(main_path, "data", "main") alt_image_path = joinpath(main_path, "data", "alt") num_classifiers = 10 - -data_file = joinpath(dirname(@__FILE__), "data", "haar-like_features_c$(num_classifiers)") diff --git a/examples/read.jl b/examples/read.jl index b3234567e..9b87312b0 100755 --- a/examples/read.jl +++ b/examples/read.jl @@ -20,22 +20,20 @@ using Printf: @printf using Images: imresize using Serialization: deserialize -println("...done") +println("...done\n") function main(; smart_choose_feats::Bool=false, - alt::Bool=false, scale::Bool=false, scale_to::Tuple=(200, 200) ) include("constants.jl") - - if ! alt - include("main_data.jl") - else - include("alt_data.jl") - end + include("main_data.jl") + + 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)") 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/")) @@ -65,4 +63,4 @@ function main(; @printf("%10.9s %10.15s %15s\n\n", "Non-faces:", non_faces_frac, non_faces_percent) end -@time main(smart_choose_feats=true, alt=false, scale=true, scale_to=(20, 20)) +@time main(smart_choose_feats=true, scale=true, scale_to=(20, 20)) diff --git a/examples/scores.jl b/examples/scores.jl index dd5d714e1..f2eb0fa9e 100755 --- a/examples/scores.jl +++ b/examples/scores.jl @@ -19,16 +19,9 @@ using Serialization: deserialize println("...done") -function main(; - smart_choose_feats::Bool=false, alt::Bool=false -) - include("constants.jl") - - if ! alt - include("main_data.jl") - else - include("alt_data.jl") - end +function main(smart_choose_feats::Bool=false) + include("constants.jl") + include("main_data.jl") # read classifiers from file classifiers = deserialize(data_file) @@ -103,4 +96,4 @@ function main(; println("...done. Plot created at ", joinpath(dirname(dirname(@__FILE__)), "figs", "scores.pdf"), "\n") end -@time main(smart_choose_feats=true, alt=false) +@time main(smart_choose_feats=true) diff --git a/examples/validation.jl b/examples/validation.jl index 57f99930c..798e84d84 100755 --- a/examples/validation.jl +++ b/examples/validation.jl @@ -23,39 +23,41 @@ println("...done") function main(; smart_choose_feats::Bool=false, - alt::Bool=false, image_reconstruction::Bool=true, - feat_validation::Bool=true + feat_validation::Bool=true, + scale::Bool=false, + scale_to::Tuple=(200, 200) ) include("constants.jl") - - if ! alt - include("main_data.jl") - else - include("alt_data.jl") - end + include("main_data.jl") + + 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)") # read classifiers from file classifiers = deserialize(data_file) - FD.notify_user("Loading test faces...") - - faces_testing = FD.load_images(pos_testing_path)[1] + # FD.notify_user("Loading test faces...") + # + # faces_testing = FD.load_images(pos_testing_path)[1] + # # faces_ii_testing = map(FD.to_integral_image, faces_testing) # faces_ii_testing = map(FD.to_integral_image, faces_testing) - faces_ii_testing = map(FD.to_integral_image, faces_testing) - println("...done. ", length(faces_testing), " faces loaded.") - - FD.notify_user("Loading test non-faces..") - - non_faces_testing = FD.load_images(neg_testing_path)[1] - non_faces_ii_testing = map(FD.to_integral_image, non_faces_testing) - println("...done. ", length(non_faces_testing), " non-faces loaded.\n") + # println("...done. ", length(faces_testing), " faces loaded.") + # + # FD.notify_user("Loading test non-faces..") + # + # non_faces_testing = FD.load_images(neg_testing_path)[1] + # non_faces_ii_testing = map(FD.to_integral_image, non_faces_testing) + # println("...done. ", length(non_faces_testing), " non-faces loaded.\n") + + random_image = get_random_image(pos_testing_path) if image_reconstruction # Just for fun: putting all Haar-like features over each other generates a face-like image FD.notify_user("Constructing an image of all Haar-like Features found...") - reconstructed_image = FD.reconstruct(classifiers, size(faces_testing[1])) + reconstructed_image = FD.reconstruct(classifiers, img_size) save(joinpath(dirname(dirname(@__FILE__)), "figs", "reconstruction.png"), Gray.(map(clamp01nan, reconstructed_image))) println("...done. See ", joinpath(dirname(dirname(@__FILE__)), "figs", "reconstruction.png"), ".\n") @@ -63,11 +65,12 @@ function main(; if feat_validation FD.notify_user("Constructing a validation image on a random image...") - - FD.generate_validation_image(FD.get_random_image(joinpath(dirname(dirname(@__FILE__)), "figs", "validation.png")), classifiers) + + validation_image = FD.generate_validation_image(random_image, classifiers) + save(joinpath(dirname(dirname(@__FILE__)), "figs", "validation.png"), validation_image) println("...done. See ", joinpath(dirname(dirname(@__FILE__)), "figs", "validation.png"), ".\n") end end -@time main(smart_choose_feats=true, alt=false, image_reconstruction=true, feat_validation=true) +@time main(smart_choose_feats=true, image_reconstruction=true, feat_validation=false) diff --git a/examples/write.jl b/examples/write.jl index 9716585c8..c0360cda6 100755 --- a/examples/write.jl +++ b/examples/write.jl @@ -19,21 +19,15 @@ const FD = FaceDetection using Printf: @printf using Serialization: serialize -println("...done") +println("...done\n") function main(; smart_choose_feats::Bool=false, - alt::Bool=false, scale::Bool=false, scale_to::Tuple=(200, 200) ) include("constants.jl") - - if ! alt - include("main_data.jl") - else - include("alt_data.jl") - end + include("main_data.jl") min_size_img = (19, 19) # default for our test dataset if smart_choose_feats @@ -54,8 +48,9 @@ function main(; 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) # write classifiers to file - data_file = joinpath(dirname(@__FILE__), "data", "haar-like_features_c$(num_classifiers)") + 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) end -@time main(smart_choose_feats=true, alt=false, scale=true, scale_to=(20, 20)) +@time main(smart_choose_feats=true, scale=true, scale_to=(20, 20)) diff --git a/src/Utils.jl b/src/Utils.jl index c2fe5b32d..a5474e4e9 100755 --- a/src/Utils.jl +++ b/src/Utils.jl @@ -9,7 +9,7 @@ include("HaarLikeFeature.jl") include("IntegralImage.jl") using Images: save, load, Colors, clamp01nan, Gray, imresize -using ImageDraw: draw!, Polygon, Point +using ImageDraw: draw, Polygon, Point #= displaymatrix(M::AbstractArray) -> AbstractString @@ -318,11 +318,11 @@ Chooses a random image from a given two directories. - `file_name::AbstractString`: The path to the file randomly chosen =# function get_random_image( - face_path::AbstractString, - non_face_path::AbstractString="", + face_path::AbstractString; + non_face_path::AbstractString=string(), non_faces::Bool=false ) - file_name = "" + file_name = string() if non_faces face = rand(Bool) @@ -364,6 +364,7 @@ function scale_box( genisis_size::Tuple{Integer, Integer}, img_size::Tuple{Integer, Integer} ) + image_ratio = (img_size[1]/genisis_size[1], img_size[2]/genisis_size[2]) bottom_left = (top_left[1], bottom_right[2]) @@ -391,158 +392,23 @@ Generates a bounding box around the face of a random image. - `validation_image::AbstractArray`: The new image with a bounding box =# -function generate_validation_image(image_path::AbstractString, classifiers::AbstractArray) - img = to_integral_image(get_image_matrix(image_path)) - img_size = size(img) - - top_left = (0,0) - bottom_right = (0,0) - bottom_left = (0,0) - top_right = (0,0) - - features = [] - - for c in classifiers - features = push!(features, (c.top_left, c.bottom_right)) - # if c.feature_type == feature_types[1] # two vertical - # features = push!(features, (c.top_left, c.bottom_right)) - # elseif c.feature_type == feature_types[2] # two horizontal - # elseif c.feature_type == feature_types[3] # three horizontal - # elseif c.feature_type == feature_types[4] # three vertical - # elseif c.feature_type == feature_types[5] # four - # end - end - - # todo: figure out rectangles over boxes. This includes finding the smallest image in size and converting the random input to that size if needed (requires importing another module). bottom right needs to have smallest y but greatest x, etc. - # todo: IF face is not a non-face, then draw box. Don't force a box. - - chosen_top_left = (0, 0) - chosen_bottom_right = (0, 0) +function generate_validation_image(image_path::AbstractString, classifiers::Array{HaarLikeObject, 1}) - for f in features # iterate through elements in features (e.g., Any[((9, 2), (17, 12)), ((11, 8), (19, 16))]) - # for t in f # iterate through inner tuples - chosen_top_left = chosen_top_left < f[1] || chosen_top_left < f[1] ? chosen_top_left : f[1] - chosen_bottom_right = chosen_bottom_right > f[2] || chosen_bottom_right > f[2] ? chosen_bottom_right : f[2] - # end - end + # === THIS FUNCTION IS A WORK IN PROGRESS === - # reasonableProportion = Int(round(0.26 * minimum(img_size))) - # - # top_left = (reasonableProportion, reasonableProportion) - # bottom_right = (img_size[1] - reasonableProportion, img_size[2] - reasonableProportion) - # bottom_left = (reasonableProportion, img_size[2] - reasonableProportion) - # top_right = (img_size[1] - reasonableProportion, reasonableProportion) + img = load_image(image_path) + img_size = size(img) - top_left = chosen_top_left - bottom_right = chosen_bottom_right - bottom_left = (chosen_top_left[1], chosen_bottom_right[2]) - top_right = (chosen_bottom_right[1], chosen_top_left[2]) + top_lefts = [c.top_left for c in classifiers] + bottom_rights = [c.bottom_right for c in classifiers] + x_coords = vcat([x[1] for x in top_lefts], [x[1] for x in bottom_rights]) + y_coords = vcat([y[2] for y in top_lefts], [y[2] for y in bottom_rights]) + min_x, max_x = extrema(x_coords) + min_y, max_y = extrema(y_coords) + top_left = min_x, min_y + bottom_right = max_x, max_y box_dimensions = scale_box(top_left, bottom_right, (19, 19), img_size) - - - - - boxes = zeros(img_size) - - for c in classifiers - # map polarity: -1 -> 0, 1 -> 1 - polarity = ((1 + c.polarity)^2)/4 - if c.feature_type == feature_types["two_vertical"] - for x in 1:c.width - sign = polarity - for y in 1:c.height - if y >= c.height/2 - sign = mod((sign + 1), 2) - end - boxes[c.top_left[2] + y, c.top_left[1] + x] += 1 * sign * c.weight - end - end - elseif c.feature_type == feature_types["two_horizontal"] - sign = polarity - for x in 1:c.width - if x >= c.width/2 - sign = mod((sign + 1), 2) - end - for y in 1:c.height - boxes[c.top_left[1] + x, c.top_left[2] + y] += 1 * sign * c.weight - end - end - elseif c.feature_type == feature_types["three_horizontal"] - sign = polarity - for x in 1:c.width - if iszero(mod(x, c.width/3)) - sign = mod((sign + 1), 2) - end - for y in 1:c.height - boxes[c.top_left[1] + x, c.top_left[2] + y] += 1 * sign * c.weight - end - end - elseif c.feature_type == feature_types["three_vertical"] - for x in 1:c.width - sign = polarity - for y in 1:c.height - if iszero(mod(x, c.height/3)) - sign = mod((sign + 1), 2) - end - boxes[c.top_left[1] + x, c.top_left[2] + y] += 1 * sign * c.weight - end - end - elseif c.feature_type == feature_types["four"] - sign = polarity - for x in 1:c.width - if iszero(mod(x, c.width/2)) - sign = mod((sign + 1), 2) - end - for y in 1:c.height - if iszero(mod(x, c.height/2)) - sign = mod((sign + 1), 2) - end - boxes[c.top_left[1] + x, c.top_left[2] + y] += 1 * sign * c.weight - end - end - end - end # end for c in classifiers - - # validationImage = load(image_path) .+ boxes - # - # println(typeof(img)) - # println(typeof(boxes)) - # println(typeof(validationImage)) - - - - # using TestImages, ImageDraw, ColorVectorSpace, ImageCore - # img = testimage("lighthouse"); - - # img = imresize(img, (19, 19)) - - # [println(c.feature_type) for c in classifiers] - # - for c in classifiers - - # box_dimensions = [c.top_left, (c.top_left[1], c.bottom_right[2]), c.bottom_right, (c.bottom_right[1], c.top_left[2])] - - box_dimensions = scale_box(c.top_left, c.bottom_right, (19, 19), img_size) - - save(joinpath(homedir(), "Desktop", "validation.png"), draw!(load(image_path), Polygon([Point(box_dimensions[1]), Point(box_dimensions[2]), Point(box_dimensions[3]), Point(box_dimensions[4])]))) - end - - - # with open('classifiers_' + str(T) + '_' + hex(random.getrandbits(16)) + '.pckl', 'wb') as file: - # pickle.dump(classifiers, file) - - # box = Polygon([Point(box_dimensions[1]), Point(box_dimensions[2]), Point(box_dimensions[3]), Point(box_dimensions[4])]) - - # return save(joinpath(homedir(), "Desktop", "validation.png"), draw!(load(image_path), box)) - -# #Arguments -# * `center::Point` : the center of the polygon -# * `side_count::Int` : number of sides of the polygon -# * `side_length::Real` : length of each side -# * `θ::Real` : orientation of the polygon w.r.t x-axis (in radians) - - - # save("/Users/jakeireland/Desktop/test.png", Gray.(map(clamp01nan, newImg))) + return draw(load(image_path), Polygon([Point(box_dimensions[1]), Point(box_dimensions[2]), Point(box_dimensions[3]), Point(box_dimensions[4])])) end