Skip to content

Commit fd5e645

Browse files
committed
refactored testing with opencv; first complete julia draft of algorithm
1 parent 4d78fc5 commit fd5e645

File tree

11 files changed

+442
-109
lines changed

11 files changed

+442
-109
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
[deps]
22
ClosedIntervals = "059b0e18-018a-5deb-a5b2-c624ee85784b"
33
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
4+
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
45
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
56
ImageFeatures = "92ff4b2b-8094-53d3-b29d-97f740f06cef"
67
ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
78
ImageTransformations = "02fcd773-0e25-5acc-982a-7f6622650795"
89
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
910
ObjectDetector = "3dfc1049-5314-49cf-8447-288dfd02f9fb"
11+
ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca"
1012
QuartzImageIO = "dca85d43-d64c-5e67-8c65-017450d5d020"
1113
TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990"

src/Adaboost.jl

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,146 @@
44
"${BASH_SOURCE[0]}" "$@"
55
=#
66

7+
using ProgressMeter
8+
using Distributed # for parallel processing (namely, @everywhere)
9+
10+
include("HaarFeatureSelection.jl")
11+
12+
13+
function learn(positiveIIs, negativeIIs, numClassifiers=-1, minFeatureWidth=1, maxFeatureWidth=-1, minFeatureHeight=1, maxFeatureHeight=-1)
14+
"""
15+
Selects a set of classifiers. Iteratively takes the best classifiers based
16+
on a weighted error.
17+
:param positive_iis: List of positive integral image examples
18+
:type positive_iis: list[numpy.ndarray]
19+
:param negative_iis: List of negative integral image examples
20+
:type negative_iis: list[numpy.ndarray]
21+
:param num_classifiers: Number of classifiers to select, -1 will use all
22+
classifiers
23+
:type num_classifiers: int
24+
:return: List of selected features
25+
:rtype: list[violajones.HaarLikeFeature.HaarLikeFeature]
26+
"""
27+
numPos = length(positiveIIs)
28+
numNeg = length(negativeIIs)
29+
numImgs = numPos + numNeg
30+
imgHeight, imgWidth = size(positiveIIs[1])
31+
32+
# Maximum feature width and height default to image width and height
33+
if isequal(maxFeatureHeight, -1)
34+
maxFeatureHeight = imgHeight
35+
else
36+
continue
37+
end
38+
if isequal(maxFeatureWidth, -1)
39+
maxFeatureWidth = imgWidth
40+
else
41+
continue
42+
end
43+
44+
# Create initial weights and labels
45+
posWeights = ones(numPos) * 1. / (2 * numPos)
46+
negWeights = ones(numNeg) * 1. / (2 * numNeg)
47+
weights = hcat((posWeights, negWeights))
48+
labels = hcat((ones(numPos), ones(numNeg) * -1))
49+
50+
images = positiveIIs + negativeIIs
51+
52+
# Create features for all sizes and locations
53+
features = _create_features(imgHeight, imgWidth, minFeatureWidth, maxFeatureWidth, minFeatureHeight, maxFeatureHeight)
54+
numFeatures = length(features)
55+
# feature_indexes = list(range(num_features))
56+
featureIndexes = Array(1:numFeatures)
57+
58+
if isequal(numClassifiers, -1)
59+
numClassifiers = numFeatures
60+
else
61+
continue
62+
end
63+
64+
votes = zeros((numImgs, numFeatures))
65+
# bar = progressbar.ProgressBar()
66+
@everywhere begin
67+
n = numImgs
68+
p = Progress(n, 1) # minimum update interval: 1 second
69+
for i in processes
70+
# votes[i, :] = np.array(pool.map(partial(_get_feature_vote, image=images[i]), features))
71+
votes[i, :] = Array(_get_feature_vote, image=images[i]), features
72+
next!(p)
73+
end
74+
end # end everywhere (end parallel processing)
75+
76+
# select classifiers
77+
classifiers = Array()
78+
79+
println('Selecting classifiers...')
80+
81+
n = numClassifiers
82+
p = Progress(n, 1) # minimum update interval: 1 second
83+
for i in processes
84+
classificationErrors = zeros(length(featureIndexes))
85+
86+
# normalize weights
87+
weights *= 1. / sum(weights)
88+
89+
# select best classifier based on the weighted error
90+
for f in 1:length(feature_indexes)
91+
fIDX = featureIndexes[f]
92+
# classifier error is the sum of image weights where the classifier
93+
# is right
94+
# error = sum(map(lambda img_idx: weights[img_idx] if labels[img_idx] != votes[img_idx, f_idx] else 0, range(num_imgs)))
95+
error = sum(imgIDX -> (labels[imgIDX] ≠ votes[imgIDX, fIDX]) ? weights[imgIDX] : 0, 1:numImgs)
96+
classificationErrors[f] = error
97+
98+
# get best feature, i.e. with smallest error
99+
minErrorIDX = argmin(classificationErrors)
100+
bestError = classificationErrors[minErrorIDX]
101+
bestFeatureIDX = featureIndexes[minErrorIDX]
102+
103+
# set feature weight
104+
bestFeature = features[bestFeatureIDX]
105+
featureWeight = 0.5 * log((1 - bestError) / bestError)
106+
bestFeature.weight = featureWeight
107+
108+
classifiers = vcat(classifiers, bestFeature)
109+
110+
# update image weights
111+
# weights = list(map(lambda img_idx: weights[img_idx] * np.sqrt((1-best_error)/best_error) if labels[img_idx] != votes[img_idx, best_feature_idx] else weights[img_idx] * np.sqrt(best_error/(1-best_error)), range(num_imgs)))
112+
weights = (imgIDX -> (labels[imgIDX] ≠ votes[imgIDX, bestFeatureIDX]) ? weights[imgIDX]*sqrt((1-bestError)/bestError) : weights[imgIDX]*sqrt(bestError/(1-bestError)), 1:numImgs)
113+
114+
# remove feature (a feature can't be selected twice)
115+
# feature_indexes.remove(best_feature_idx)
116+
featureIndexes = filter!(e -> e ∉ bestFeatureIDX, featureIndexes) # note: without unicode operators, `e ∉ [a, b]` is `!(e in [a, b])`
117+
118+
next!(p)
119+
end
120+
121+
return classifiers
122+
end
123+
124+
125+
function _get_feature_vote(feature, image)
126+
return vote(image)
127+
end
128+
129+
130+
function _create_features(imgHeight::Int64, imgWidth::Int64, minFeatureWidth::Int64, maxFeatureWidth::Int64, minFeatureHeight::Int64, maxFeatureHeight::Int64)
131+
println("Creating Haar-like features...")
132+
features = Array()
133+
134+
for feature in FeatureTypes
135+
featureStartWidth = max(minFeatureWidth, feature[1])
136+
for featureWidth in range(featureStartWidth, stop=maxFeatureWidth, step=feature[1])
137+
for x in 1:(imgWidth - featureWidth)
138+
for y in 1:(imgHeight - featureHeight)
139+
"""features.append(HaarLikeFeature(feature, (x, y), feature_width, feature_height, 0, 1))
140+
features.append(HaarLikeFeature(feature, (x, y), feature_width, feature_height, 0, -1))"""
141+
end # end for y
142+
end # end for x
143+
end # end for feature width
144+
end # end for feature in feature types
145+
146+
println('...finished processing; ' + str(len(features)) + ' features created.')
147+
148+
return features
149+
end

src/HaarFeatureSelection.jl

Lines changed: 106 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,71 @@ include("IntegralImage.jl")
1111
# FeatureType = enum(TWO_VERTICAL=(1, 2), TWO_HORIZONTAL=(2, 1), THREE_HORIZONTAL=(3, 1), THREE_VERTICAL=(1, 3), FOUR=(2, 2))
1212
# FeatureTypes = Array(FeatureType.TWO_VERTICAL, FeatureType.TWO_HORIZONTAL, FeatureType.THREE_VERTICAL, FeatureType.THREE_HORIZONTAL, FeatureType.FOUR)
1313

14-
FeatureType = Dict{String, AbstractArray}("two_vertical" => (1, 2), "two_horizontal" => (2, 1), "three_horizontal" => (3,1), "three_vertical" => (1,3), "four" => (2, 2))
14+
FeatureType = Dict{String, Tuple{Int64,Int64}}("two_vertical" => (1, 2), "two_horizontal" => (2, 1), "three_horizontal" => (3,1), "three_vertical" => (1,3), "four" => (2, 2))
1515
FeatureTypes = [FeatureType["two_vertical"], FeatureType["two_horizontal"], FeatureType["three_horizontal"], FeatureType["three_vertical"], FeatureType["four"]]
1616

1717

18-
abstract type HaarType end
18+
abstract type HaarObject end
19+
#
20+
#
21+
# struct HaarLikeFeature <: HaarType
22+
# feature_type::Any
23+
# position::Array
24+
# topLeft::Array
25+
# bottomRight::Array
26+
# width::Int64
27+
# height::Int64
28+
# threshold::Float64
29+
# polarity::Int64
30+
# weight::Float64
31+
#
32+
# # constructor; equivalent of __init__ method within class
33+
# function HaarLikeFeature(feature_type::Any, position::Array, width::Int64, height::Int64, threshold::Float64, polarity::Int64, weight::Float64)
34+
# topLeft = position
35+
# bottomRight = (position[1] + width, position[2] + height)
36+
# weight = 1
37+
# new(feature_type, topLeft, bottomRight, width, height, threshold, polarity)
38+
# end # end constructor
39+
# end # end structure
40+
#
41+
#
42+
# #
43+
# function getScore(self::HaarLikeFeature, intImg::AbstractArray)
44+
# """
45+
# Get score for given integral image array.
46+
# :param int_img: Integral image array
47+
# :type int_img: numpy.ndarray
48+
# :return: Score for given feature
49+
# :rtype: float
50+
# """
51+
# # set instance of score outside of ifs
52+
# score = 0
53+
#
54+
# if self.feature_type == FeatureType["two_vertical"]
55+
# first = sumRegion(intImg, self.top_left, (self.top_left[1] + self.width, Int(self.top_left[2] + self.height / 2)))
56+
# second = sumRegion(int_img, (self.top_left[1], Int(self.top_left[2] + self.height / 2)), self.bottom_right)
57+
# score = first - second
58+
# end
59+
# return score
60+
#
61+
# end # end getScore function
1962

2063

21-
struct HaarLikeFeature <: HaarType
22-
feature_type::Any
23-
position::Array
24-
topLeft::Array
25-
bottomRight::Array
64+
abstract type HaarFeatureType end
65+
66+
# make structure
67+
struct HaarLikeFeature <: HaarFeatureType#struct HaarLikeFeature{T} <: HaarObject where {T <: HaarFeatureType}
68+
position::Tuple{Int64, Int64}
69+
topLeft::Tuple{Int64, Int64}
70+
bottomRight::Tuple{Int64, Int64}
2671
width::Int64
2772
height::Int64
2873
threshold::Float64
2974
polarity::Int64
3075
weight::Float64
3176

3277
# constructor; equivalent of __init__ method within class
33-
function HaarLikeFeature(feature_type::Any, position::Array, width::Int64, height::Int64, threshold::Float64, polarity::Int64, weight::Float64)
78+
function HaarLikeFeature(position::Tuple{Int64, Int64}, width::Int64, height::Int64, threshold::Float64, polarity::Int64, weight::Float64)
3479
topLeft = position
3580
bottomRight = (position[1] + width, position[2] + height)
3681
weight = 1
@@ -39,85 +84,71 @@ struct HaarLikeFeature <: HaarType
3984
end # end structure
4085

4186

42-
#
43-
function getScore(self::HaarLikeFeature, intImg::AbstractArray)
44-
"""
45-
Get score for given integral image array.
46-
:param int_img: Integral image array
47-
:type int_img: numpy.ndarray
48-
:return: Score for given feature
49-
:rtype: float
50-
"""
51-
# set instance of score outside of ifs
52-
score = 0
53-
54-
if self.feature_type == FeatureType["two_vertical"]
55-
first = sumRegion(intImg, self.top_left, (self.top_left[1] + self.width, Int(self.top_left[2] + self.height / 2)))
56-
second = sumRegion(int_img, (self.top_left[1], Int(self.top_left[2] + self.height / 2)), self.bottom_right)
57-
score = first - second
58-
end
59-
return score
60-
61-
end # end getScore function
62-
87+
# define the various Haar like feature types
88+
struct HaarFeatureTwoVertical <: HaarFeatureType end
89+
struct HaarFeatureTwoHorizontal <: HaarFeatureType end
90+
struct HaarFeatureThreeHorizontal <: HaarFeatureType end
91+
struct HaarFeatureThreeVertical <: HaarFeatureType end
92+
struct HaarFeatureFour <: HaarFeatureType end
6393

6494

65-
imgArr = getImageMatrix()
66-
integralImageArr = toIntegralImage(imgArr)
95+
# HaarFeatureTwoVertical = (1, 2)
6796

68-
# println(integralImageArr)
6997

70-
output = getScore(integralImageArr)
98+
# construct integral image
99+
intImg = toIntegralImage(getImageMatrix())
71100

72-
println(output)
101+
function score(::HaarFeatureTwoVertical, self::HaarLikeFeature)
102+
first = sumRegion(intImg, self.top_left, (self.top_left[1] + self.width, Int(self.top_left[2] + self.height / 2)))
103+
second = sumRegion(intImg, (self.top_left[1], Int(self.top_left[2] + self.height / 2)), self.bottom_right)
104+
score = first - second
105+
return score
106+
end
73107

74-
# x = new HaarLikeFeature()
108+
function score(::HaarFeatureTwoHorizontal, self::HaarLikeFeature)
109+
first = sumRegion(intImg, self.top_left, (int(self.top_left[1] + self.width / 3), self.top_left[2] + self.height))
110+
second = sumRegion(intImg, (Int(self.top_left[1] + self.width / 3), self.top_left[1]), (Int(self.top_left[1] + 2 * self.width / 3), self.top_left[2] + self.height))
111+
third = sumRegion(intImg, (Int(self.top_left[1] + 2 * self.width / 3), self.top_left[2]), self.bottom_right)
112+
score = first - second + third
113+
return score
114+
end
75115

76-
# function Base.show(io::IO, gs::HaarLikeFeature)
77-
# println(io, getScore(gs))
78-
# end
79-
#
80-
# show(integralImageArr)
116+
function score(::HaarFeatureThreeHorizontal, self::HaarLikeFeature)
117+
first = sumRegion(intImg, self.top_left, (Int(self.top_left[1] + self.width / 3), self.top_left[2] + self.height))
118+
second = sumRegion(intImg, (Int(self.top_left[1] + self.width / 3), self.top_left[2]), (Int(self.top_left[1] + 2 * self.width / 3), self.top_left[2] + self.height))
119+
third = sumRegion(intImg, (Int(self.top_left[1] + 2 * self.width / 3), self.top_left[2]), self.bottom_right)
120+
score = first - second + third
121+
return score
122+
end
81123

82-
# def _get_feature_vote(feature, image):
83-
# return feature.get_vote(image)
124+
function score(::HaarFeatureThreeVertical, self::HaarLikeFeature)
125+
first = sumRegion(intImg, self.top_left, (self.bottom_right[1], Int(self.top_left[2] + self.height / 3)))
126+
second = sumRegion(intImg, (self.top_left[1], Int(self.top_left[2] + self.height / 3)), (self.bottom_right[1], Int(self.top_left[2] + 2 * self.height / 3)))
127+
third = sumRegion(intImg, (self.top_left[1], Int(self.top_left[2] + 2 * self.height / 3)), self.bottom_right)
128+
score = first - second + third
129+
return score
130+
end
84131

85-
# x.getScore(integralImageArr)
132+
function score(::HaarFeatureFour, self::HaarLikeFeature)
133+
# top left area
134+
first = sumRegion(intImg, self.top_left, (Int(self.top_left[1] + self.width / 2), Int(self.top_left[2] + self.height / 2)))
135+
# top right area
136+
second = sumRegion(intImg, (Int(self.top_left[1] + self.width / 2), self.top_left[2]), (self.bottom_right[1], Int(self.top_left[2] + self.height / 2)))
137+
# bottom left area
138+
third = sumRegion(intImg, (self.top_left[1], Int(self.top_left[2] + self.height / 2)), (Int(self.top_left[1] + self.width / 2), self.bottom_right[2]))
139+
# bottom right area
140+
fourth = sumRegion(intImg, (Int(self.top_left[1] + self.width / 2), int(self.top_left[2] + self.height / 2)), self.bottom_right)
141+
score = first - second - third + fourth
142+
return score
143+
end
86144

87-
abstract type HaarFeatureType end
88145

89-
struct HaarLikeFeature <: HaarType
90-
position::Array{Int64, 2}
91-
topLeft::Array{Int64, 2}
92-
bottomRight::Array{Int64, 2}
93-
width::Int64
94-
height::Int64
95-
threshold::Float64
96-
polarity::Int64
97-
weight::Float64
98-
99-
# constructor; equivalent of __init__ method within class
100-
function HaarLikeFeature(position::Array, width::Int64, height::Int64, threshold::Float64, polarity::Int64, weight::Float64)
101-
topLeft = position
102-
bottomRight = (position[1] + width, position[2] + height)
103-
weight = 1
104-
new(feature_type, topLeft, bottomRight, width, height, threshold, polarity)
105-
end # end constructor
106-
end # end structure
107146

147+
# imgArr = getImageMatrix()
148+
# integralImageArr = toIntegralImage(imgArr)
108149

109-
struct HaarFeatureTwoVertical <: HaarFeatureType end
110-
struct HaarFeatureTwoHorizontal <: HaarFeatureType end
150+
# println(integralImageArr)
111151

112-
function score(::HaarFeatureTwoVertical, self::HaarLikeFeature)
113-
first = ii.sum_region(int_img, self.top_left, (self.top_left[0] + self.width, int(self.top_left[1] + self.height / 2)))
114-
second = ii.sum_region(int_img, (self.top_left[0], int(self.top_left[1] + self.height / 2)), self.bottom_right)
115-
return first - second
116-
end
152+
output = score(intImg)
117153

118-
function score(::HaarFeatureTwoHoritontal, self::HaarLikeFeature)
119-
first = ii.sum_region(int_img, self.top_left, (int(self.top_left[0] + self.width / 3), self.top_left[1] + self.height))
120-
second = ii.sum_region(int_img, (int(self.top_left[0] + self.width / 3), self.top_left[1]), (int(self.top_left[0] + 2 * self.width / 3), self.top_left[1] + self.height))
121-
third = ii.sum_region(int_img, (int(self.top_left[0] + 2 * self.width / 3), self.top_left[1]), self.bottom_right)
122-
return first - second + third
123-
end
154+
println(output)

0 commit comments

Comments
 (0)