Skip to content

Commit

Permalink
changed the way we filter dups in dpm and icf
Browse files Browse the repository at this point in the history
  • Loading branch information
liuliu committed Sep 2, 2013
1 parent 8cb51aa commit 0cc48c2
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 48 deletions.
56 changes: 28 additions & 28 deletions bin/dpmvldtr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,35 @@
truth = Hash.new
total = 0

File.new(ARGV[0]).each_line do |line|
args = line.split " "
name, x, y, width, height = args[0].to_s, args[1].to_i, args[2].to_i, args[3].to_i, args[4].to_i
# next if width < 44 or height < 28
truth[name] = Array.new unless truth.has_key? name
truth[name] << { :found => false, :x => x, :y => y, :width => width, :height => height }
end

truth.each do |name, boxes|
total += boxes.count
end
# File.new(ARGV[0]).each_line do |line|
# args = line.split " "
# name, x, y, width, height = args[0].to_s, args[1].to_i, args[2].to_i, args[3].to_i, args[4].to_i
# # next if width < 44 or height < 28
# truth[name] = Array.new unless truth.has_key? name
# truth[name] << { :found => false, :x => x, :y => y, :width => width, :height => height }
# end
#
# truth.each do |name, boxes|
# total += boxes.count
# end

# files = Dir.glob(ARGV[0] + '/*.txt')
files = Dir.glob(ARGV[0] + '/*.txt')

# files.each do |file|
# name = nil;
# boxes = Array.new
# File.new(file).each_line do |line|
# next if line[0] == '#'
# name = line[line.rindex('/') + 1, line.rindex('"') - (line.rindex('/') + 1)] if line[0, 14].downcase == "image filename"
# if line[0, 16].downcase == "bounding box for"
# i = line.scan(/object\s*(\d+)/)[0][0].to_i
# coord = line.scan(/\((\d+),\s*(\d+)\)\s*-\s*\((\d+),\s*(\d+)\)/)[0]
# boxes[i - 1] = { :found => false, :x => coord[0].to_i, :y => coord[1].to_i, :width => coord[2].to_i - coord[0].to_i, :height => coord[3].to_i - coord[1].to_i }
# end
# end
# truth[name] = boxes;
# total += boxes.length;
# end
files.each do |file|
name = nil;
boxes = Array.new
File.new(file).each_line do |line|
next if line[0] == '#'
name = line[line.rindex('/') + 1, line.rindex('"') - (line.rindex('/') + 1)] if line[0, 14].downcase == "image filename"
if line[0, 16].downcase == "bounding box for"
i = line.scan(/object\s*(\d+)/)[0][0].to_i
coord = line.scan(/\((\d+),\s*(\d+)\)\s*-\s*\((\d+),\s*(\d+)\)/)[0]
boxes[i - 1] = { :found => false, :x => coord[0].to_i, :y => coord[1].to_i, :width => coord[2].to_i - coord[0].to_i, :height => coord[3].to_i - coord[1].to_i }
end
end
truth[name] = boxes;
total += boxes.length;
end

fa = 0
tp = 0
Expand All @@ -42,7 +42,7 @@
next if line[0] == '|'
args = line.split " "
name = args[0].to_s
# name = args[0][args[0].rindex('/') + 1, args[0].length - (args[0].rindex('/') + 1)]
name = args[0][args[0].rindex('/') + 1, args[0].length - (args[0].rindex('/') + 1)]
if !truth[name]
fa += 1
else
Expand Down
2 changes: 1 addition & 1 deletion bin/icfdraw.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
rect += sprintf("-draw \"rectangle %d,%d %d,%d\" ", x, y, x + width, y + height)
end

%x[#{sprintf("convert %s -fill none -stroke red -strokewidth 2 %s%s", ARGV[0], rect, ARGV[1])}]
%x[#{sprintf("convert %s -fill none -stroke lime -strokewidth 2 %s%s", ARGV[0], rect, ARGV[1])}]
2 changes: 1 addition & 1 deletion bin/icfoptimize.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ int main(int argc, char** argv)
free(file);
ccv_icf_classifier_cascade_t* cascade = ccv_icf_read_classifier_cascade(classifier_cascade);
assert(cascade && "classifier cascade doesn't exists");
ccv_icf_classifier_cascade_soft(cascade, posfiles, classifier_cascade, acceptance);
ccv_icf_classifier_cascade_soft(cascade, posfiles, acceptance);
ccv_icf_write_classifier_cascade(cascade, classifier_cascade);
for (i = 0; i < posfiles->rnum; i++)
{
Expand Down
11 changes: 6 additions & 5 deletions doc/dpm.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,20 @@ area among the two), it will be counted as a true positive. Otherwise, it will b
counted as a false positive (false alarm).

Another implementation is from the DPM inventor, it is a Matlab implementation,
and the author has a specially trained detector for INRIA 2008 dataset.
and the author has a specially trained detector for INRIA 2008 dataset (at -0.3
threshold).

75.21% (74)
75.38% (55)

The DPM implementation in ccv was trained for three days using the default parameters
with INRIA training data. Let's see how it performs.

./dpmdetect filelist.txt ../samples/pedestrian.m > result.txt
./dpmvldtr.rb <INRIA dataset>/Test/annotations result.txt

The result is:
The result is (at 0.8 threshold):

76.4% (68)
76.74% (49)

Speed-wise:

Expand Down Expand Up @@ -124,4 +125,4 @@ I've trained one more mixture model: samples/car.m

It has been trained with VOC2011 trainval dataset, and the result on validation dataset:

46.19% (16)
46.19% (16)
2 changes: 1 addition & 1 deletion doc/icf.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ The provided model is then tested with INRIA 2008 test dataset, if bounding boxe
overlap is greater than 0.5 of the bigger bounding boxes, it is a true positive.
The validation script is available at ./bin/icfvldtr.rb.

77.25% (66)
76.23% (52)

Which has slightly higher recall than DPM implementation provided in ccv, with higher
false alarms too.
Expand Down
2 changes: 1 addition & 1 deletion lib/ccv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1055,7 +1055,7 @@ void ccv_icf(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type);

/* ICF for single scale */
ccv_icf_classifier_cascade_t* __attribute__((warn_unused_result)) ccv_icf_classifier_cascade_new(ccv_array_t* posfiles, int posnum, ccv_array_t* bgfiles, int negnum, ccv_array_t* testfiles, const char* dir, ccv_icf_new_param_t params);
void ccv_icf_classifier_cascade_soft(ccv_icf_classifier_cascade_t* cascade, ccv_array_t* posfiles, const char* dir, double acceptance);
void ccv_icf_classifier_cascade_soft(ccv_icf_classifier_cascade_t* cascade, ccv_array_t* posfiles, double acceptance);
ccv_icf_classifier_cascade_t* __attribute__((warn_unused_result)) ccv_icf_read_classifier_cascade(const char* filename);
void ccv_icf_write_classifier_cascade(ccv_icf_classifier_cascade_t* classifier, const char* filename);
void ccv_icf_classifier_cascade_free(ccv_icf_classifier_cascade_t* classifier);
Expand Down
31 changes: 27 additions & 4 deletions lib/ccv_dpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const ccv_dpm_param_t ccv_dpm_default_params = {
.interval = 8,
.min_neighbors = 1,
.flags = 0,
.threshold = 0.6,
.threshold = 0.6, // 0.8
};

#define CCV_DPM_WINDOW_SIZE (8)
Expand Down Expand Up @@ -2085,7 +2085,7 @@ ccv_array_t* ccv_dpm_detect_objects(ccv_dense_matrix_t* a, ccv_dpm_mixture_model
if (f_ptr[x] + root->beta > params.threshold)
{
ccv_root_comp_t comp;
comp.id = c;
comp.id = c + 1;
comp.neighbors = 1;
comp.confidence = f_ptr[x] + root->beta;
comp.pnum = root->count;
Expand Down Expand Up @@ -2170,6 +2170,29 @@ ccv_array_t* ccv_dpm_detect_objects(ccv_dense_matrix_t* a, ccv_dpm_mixture_model
ccv_array_push(seq2, comps + i);
}

// filter out large object rectangles contains small object rectangles
for(i = 0; i < seq2->rnum; i++)
{
ccv_root_comp_t* r2 = (ccv_root_comp_t*)ccv_array_get(seq2, i);
int distance = (int)(ccv_min(r2->rect.width, r2->rect.height) * 0.25 + 0.5);
for(j = 0; j < seq2->rnum; j++)
{
ccv_root_comp_t r1 = *(ccv_root_comp_t*)ccv_array_get(seq2, j);
if (i != j &&
abs(r1.id) == r2->id &&
r1.rect.x >= r2->rect.x - distance &&
r1.rect.y >= r2->rect.y - distance &&
r1.rect.x + r1.rect.width <= r2->rect.x + r2->rect.width + distance &&
r1.rect.y + r1.rect.height <= r2->rect.y + r2->rect.height + distance &&
// if r1 (the smaller one) is better, mute r2
(r2->confidence <= r1.confidence && r2->neighbors < r1.neighbors))
{
r2->id = -r2->id;
break;
}
}
}

// filter out small object rectangles inside large object rectangles
for(i = 0; i < seq2->rnum; i++)
{
Expand All @@ -2182,7 +2205,7 @@ ccv_array_t* ccv_dpm_detect_objects(ccv_dense_matrix_t* a, ccv_dpm_mixture_model
int distance = (int)(ccv_min(r2.rect.width, r2.rect.height) * 0.25 + 0.5);

if (i != j &&
r1.id == r2.id &&
abs(r1.id) == abs(r2.id) &&
r1.rect.x >= r2.rect.x - distance &&
r1.rect.y >= r2.rect.y - distance &&
r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance &&
Expand All @@ -2194,7 +2217,7 @@ ccv_array_t* ccv_dpm_detect_objects(ccv_dense_matrix_t* a, ccv_dpm_mixture_model
}
}

if(flag)
if(flag && r1->id > 0)
ccv_array_push(result_seq, &r1);
}
ccv_array_free(idx_seq);
Expand Down
38 changes: 31 additions & 7 deletions lib/ccv_icf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1532,7 +1532,7 @@ ccv_icf_classifier_cascade_t* ccv_icf_classifier_cascade_new(ccv_array_t* posfil
return z.classifier;
}

void ccv_icf_classifier_cascade_soft(ccv_icf_classifier_cascade_t* cascade, ccv_array_t* posfiles, const char* dir, double acceptance)
void ccv_icf_classifier_cascade_soft(ccv_icf_classifier_cascade_t* cascade, ccv_array_t* posfiles, double acceptance)
{
printf("with %d positive examples\n"
"going to accept %.2lf%% positive examples\n",
Expand Down Expand Up @@ -1798,7 +1798,7 @@ static void _ccv_icf_detect_objects_with_classifier_cascade(ccv_dense_matrix_t*
{
ccv_comp_t comp;
comp.rect = ccv_rect((int)((x + 0.5) * scale * (1 << i) - 0.5), (int)((y + 0.5) * scale * (1 << i) - 0.5), (cascade->size.width - cascade->margin.left - cascade->margin.right) * scale * (1 << i), (cascade->size.height - cascade->margin.top - cascade->margin.bottom) * scale * (1 << i));
comp.id = j;
comp.id = j + 1;
comp.neighbors = 1;
comp.confidence = sum;
ccv_array_push(seq[j], &comp);
Expand Down Expand Up @@ -1905,7 +1905,7 @@ static void _ccv_icf_detect_objects_with_multiscale_classifier_cascade(ccv_dense
{
ccv_comp_t comp;
comp.rect = ccv_rect((int)((x + 0.5) * scale * (1 << i)), (int)((y + 0.5) * scale * (1 << i)), (cascade->size.width - cascade->margin.left - cascade->margin.right) << i, (cascade->size.height - cascade->margin.top - cascade->margin.bottom) << i);
comp.id = j;
comp.id = j + 1;
comp.neighbors = 1;
comp.confidence = sum;
ccv_array_push(seq[j], &comp);
Expand Down Expand Up @@ -1987,31 +1987,55 @@ ccv_array_t* ccv_icf_detect_objects(ccv_dense_matrix_t* a, void* cascade, int co
ccv_array_push(seq2, comps + i);
}

// filter out large object rectangles contains small object rectangles
for(i = 0; i < seq2->rnum; i++)
{
ccv_comp_t* r2 = (ccv_comp_t*)ccv_array_get(seq2, i);
int distance = (int)(ccv_min(r2->rect.width, r2->rect.height) * 0.25 + 0.5);
for(j = 0; j < seq2->rnum; j++)
{
ccv_comp_t r1 = *(ccv_comp_t*)ccv_array_get(seq2, j);
if (i != j &&
abs(r1.id) == r2->id &&
r1.rect.x >= r2->rect.x - distance &&
r1.rect.y >= r2->rect.y - distance &&
r1.rect.x + r1.rect.width <= r2->rect.x + r2->rect.width + distance &&
r1.rect.y + r1.rect.height <= r2->rect.y + r2->rect.height + distance &&
// if r1 (the smaller one) is better, mute r2
(r2->confidence <= r1.confidence && r2->neighbors < r1.neighbors))
{
r2->id = -r2->id;
break;
}
}
}

// filter out small object rectangles inside large object rectangles
for(i = 0; i < seq2->rnum; i++)
{
ccv_root_comp_t r1 = *(ccv_root_comp_t*)ccv_array_get(seq2, i);
ccv_comp_t r1 = *(ccv_comp_t*)ccv_array_get(seq2, i);
int flag = 1;

for(j = 0; j < seq2->rnum; j++)
{
ccv_root_comp_t r2 = *(ccv_root_comp_t*)ccv_array_get(seq2, j);
ccv_comp_t r2 = *(ccv_comp_t*)ccv_array_get(seq2, j);
int distance = (int)(ccv_min(r2.rect.width, r2.rect.height) * 0.25 + 0.5);

if (i != j &&
r1.id == r2.id &&
abs(r1.id) == abs(r2.id) &&
r1.rect.x >= r2.rect.x - distance &&
r1.rect.y >= r2.rect.y - distance &&
r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance &&
r1.rect.y + r1.rect.height <= r2.rect.y + r2.rect.height + distance &&
// if r2 is better, we mute r1
(r2.confidence > r1.confidence || r2.neighbors >= r1.neighbors))
{
flag = 0;
break;
}
}

if(flag)
if(flag && r1->id > 0)
ccv_array_push(result_seq, &r1);
}
ccv_array_free(idx_seq);
Expand Down

0 comments on commit 0cc48c2

Please sign in to comment.