Skip to content

Commit 0cc48c2

Browse files
committed
changed the way we filter dups in dpm and icf
1 parent 8cb51aa commit 0cc48c2

File tree

8 files changed

+96
-48
lines changed

8 files changed

+96
-48
lines changed

bin/dpmvldtr.rb

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,35 @@
55
truth = Hash.new
66
total = 0
77

8-
File.new(ARGV[0]).each_line do |line|
9-
args = line.split " "
10-
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
11-
# next if width < 44 or height < 28
12-
truth[name] = Array.new unless truth.has_key? name
13-
truth[name] << { :found => false, :x => x, :y => y, :width => width, :height => height }
14-
end
15-
16-
truth.each do |name, boxes|
17-
total += boxes.count
18-
end
8+
# File.new(ARGV[0]).each_line do |line|
9+
# args = line.split " "
10+
# 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
11+
# # next if width < 44 or height < 28
12+
# truth[name] = Array.new unless truth.has_key? name
13+
# truth[name] << { :found => false, :x => x, :y => y, :width => width, :height => height }
14+
# end
15+
#
16+
# truth.each do |name, boxes|
17+
# total += boxes.count
18+
# end
1919

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

22-
# files.each do |file|
23-
# name = nil;
24-
# boxes = Array.new
25-
# File.new(file).each_line do |line|
26-
# next if line[0] == '#'
27-
# name = line[line.rindex('/') + 1, line.rindex('"') - (line.rindex('/') + 1)] if line[0, 14].downcase == "image filename"
28-
# if line[0, 16].downcase == "bounding box for"
29-
# i = line.scan(/object\s*(\d+)/)[0][0].to_i
30-
# coord = line.scan(/\((\d+),\s*(\d+)\)\s*-\s*\((\d+),\s*(\d+)\)/)[0]
31-
# 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 }
32-
# end
33-
# end
34-
# truth[name] = boxes;
35-
# total += boxes.length;
36-
# end
22+
files.each do |file|
23+
name = nil;
24+
boxes = Array.new
25+
File.new(file).each_line do |line|
26+
next if line[0] == '#'
27+
name = line[line.rindex('/') + 1, line.rindex('"') - (line.rindex('/') + 1)] if line[0, 14].downcase == "image filename"
28+
if line[0, 16].downcase == "bounding box for"
29+
i = line.scan(/object\s*(\d+)/)[0][0].to_i
30+
coord = line.scan(/\((\d+),\s*(\d+)\)\s*-\s*\((\d+),\s*(\d+)\)/)[0]
31+
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 }
32+
end
33+
end
34+
truth[name] = boxes;
35+
total += boxes.length;
36+
end
3737

3838
fa = 0
3939
tp = 0
@@ -42,7 +42,7 @@
4242
next if line[0] == '|'
4343
args = line.split " "
4444
name = args[0].to_s
45-
# name = args[0][args[0].rindex('/') + 1, args[0].length - (args[0].rindex('/') + 1)]
45+
name = args[0][args[0].rindex('/') + 1, args[0].length - (args[0].rindex('/') + 1)]
4646
if !truth[name]
4747
fa += 1
4848
else

bin/icfdraw.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414
rect += sprintf("-draw \"rectangle %d,%d %d,%d\" ", x, y, x + width, y + height)
1515
end
1616

17-
%x[#{sprintf("convert %s -fill none -stroke red -strokewidth 2 %s%s", ARGV[0], rect, ARGV[1])}]
17+
%x[#{sprintf("convert %s -fill none -stroke lime -strokewidth 2 %s%s", ARGV[0], rect, ARGV[1])}]

bin/icfoptimize.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ int main(int argc, char** argv)
8383
free(file);
8484
ccv_icf_classifier_cascade_t* cascade = ccv_icf_read_classifier_cascade(classifier_cascade);
8585
assert(cascade && "classifier cascade doesn't exists");
86-
ccv_icf_classifier_cascade_soft(cascade, posfiles, classifier_cascade, acceptance);
86+
ccv_icf_classifier_cascade_soft(cascade, posfiles, acceptance);
8787
ccv_icf_write_classifier_cascade(cascade, classifier_cascade);
8888
for (i = 0; i < posfiles->rnum; i++)
8989
{

doc/dpm.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,20 @@ area among the two), it will be counted as a true positive. Otherwise, it will b
4747
counted as a false positive (false alarm).
4848

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

52-
75.21% (74)
53+
75.38% (55)
5354

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

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

60-
The result is:
61+
The result is (at 0.8 threshold):
6162

62-
76.4% (68)
63+
76.74% (49)
6364

6465
Speed-wise:
6566

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

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

127-
46.19% (16)
128+
46.19% (16)

doc/icf.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ The provided model is then tested with INRIA 2008 test dataset, if bounding boxe
5656
overlap is greater than 0.5 of the bigger bounding boxes, it is a true positive.
5757
The validation script is available at ./bin/icfvldtr.rb.
5858

59-
77.25% (66)
59+
76.23% (52)
6060

6161
Which has slightly higher recall than DPM implementation provided in ccv, with higher
6262
false alarms too.

lib/ccv.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1055,7 +1055,7 @@ void ccv_icf(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type);
10551055

10561056
/* ICF for single scale */
10571057
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);
1058-
void ccv_icf_classifier_cascade_soft(ccv_icf_classifier_cascade_t* cascade, ccv_array_t* posfiles, const char* dir, double acceptance);
1058+
void ccv_icf_classifier_cascade_soft(ccv_icf_classifier_cascade_t* cascade, ccv_array_t* posfiles, double acceptance);
10591059
ccv_icf_classifier_cascade_t* __attribute__((warn_unused_result)) ccv_icf_read_classifier_cascade(const char* filename);
10601060
void ccv_icf_write_classifier_cascade(ccv_icf_classifier_cascade_t* classifier, const char* filename);
10611061
void ccv_icf_classifier_cascade_free(ccv_icf_classifier_cascade_t* classifier);

lib/ccv_dpm.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const ccv_dpm_param_t ccv_dpm_default_params = {
1717
.interval = 8,
1818
.min_neighbors = 1,
1919
.flags = 0,
20-
.threshold = 0.6,
20+
.threshold = 0.6, // 0.8
2121
};
2222

2323
#define CCV_DPM_WINDOW_SIZE (8)
@@ -2085,7 +2085,7 @@ ccv_array_t* ccv_dpm_detect_objects(ccv_dense_matrix_t* a, ccv_dpm_mixture_model
20852085
if (f_ptr[x] + root->beta > params.threshold)
20862086
{
20872087
ccv_root_comp_t comp;
2088-
comp.id = c;
2088+
comp.id = c + 1;
20892089
comp.neighbors = 1;
20902090
comp.confidence = f_ptr[x] + root->beta;
20912091
comp.pnum = root->count;
@@ -2170,6 +2170,29 @@ ccv_array_t* ccv_dpm_detect_objects(ccv_dense_matrix_t* a, ccv_dpm_mixture_model
21702170
ccv_array_push(seq2, comps + i);
21712171
}
21722172

2173+
// filter out large object rectangles contains small object rectangles
2174+
for(i = 0; i < seq2->rnum; i++)
2175+
{
2176+
ccv_root_comp_t* r2 = (ccv_root_comp_t*)ccv_array_get(seq2, i);
2177+
int distance = (int)(ccv_min(r2->rect.width, r2->rect.height) * 0.25 + 0.5);
2178+
for(j = 0; j < seq2->rnum; j++)
2179+
{
2180+
ccv_root_comp_t r1 = *(ccv_root_comp_t*)ccv_array_get(seq2, j);
2181+
if (i != j &&
2182+
abs(r1.id) == r2->id &&
2183+
r1.rect.x >= r2->rect.x - distance &&
2184+
r1.rect.y >= r2->rect.y - distance &&
2185+
r1.rect.x + r1.rect.width <= r2->rect.x + r2->rect.width + distance &&
2186+
r1.rect.y + r1.rect.height <= r2->rect.y + r2->rect.height + distance &&
2187+
// if r1 (the smaller one) is better, mute r2
2188+
(r2->confidence <= r1.confidence && r2->neighbors < r1.neighbors))
2189+
{
2190+
r2->id = -r2->id;
2191+
break;
2192+
}
2193+
}
2194+
}
2195+
21732196
// filter out small object rectangles inside large object rectangles
21742197
for(i = 0; i < seq2->rnum; i++)
21752198
{
@@ -2182,7 +2205,7 @@ ccv_array_t* ccv_dpm_detect_objects(ccv_dense_matrix_t* a, ccv_dpm_mixture_model
21822205
int distance = (int)(ccv_min(r2.rect.width, r2.rect.height) * 0.25 + 0.5);
21832206

21842207
if (i != j &&
2185-
r1.id == r2.id &&
2208+
abs(r1.id) == abs(r2.id) &&
21862209
r1.rect.x >= r2.rect.x - distance &&
21872210
r1.rect.y >= r2.rect.y - distance &&
21882211
r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance &&
@@ -2194,7 +2217,7 @@ ccv_array_t* ccv_dpm_detect_objects(ccv_dense_matrix_t* a, ccv_dpm_mixture_model
21942217
}
21952218
}
21962219

2197-
if(flag)
2220+
if(flag && r1->id > 0)
21982221
ccv_array_push(result_seq, &r1);
21992222
}
22002223
ccv_array_free(idx_seq);

lib/ccv_icf.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,7 +1532,7 @@ ccv_icf_classifier_cascade_t* ccv_icf_classifier_cascade_new(ccv_array_t* posfil
15321532
return z.classifier;
15331533
}
15341534

1535-
void ccv_icf_classifier_cascade_soft(ccv_icf_classifier_cascade_t* cascade, ccv_array_t* posfiles, const char* dir, double acceptance)
1535+
void ccv_icf_classifier_cascade_soft(ccv_icf_classifier_cascade_t* cascade, ccv_array_t* posfiles, double acceptance)
15361536
{
15371537
printf("with %d positive examples\n"
15381538
"going to accept %.2lf%% positive examples\n",
@@ -1798,7 +1798,7 @@ static void _ccv_icf_detect_objects_with_classifier_cascade(ccv_dense_matrix_t*
17981798
{
17991799
ccv_comp_t comp;
18001800
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));
1801-
comp.id = j;
1801+
comp.id = j + 1;
18021802
comp.neighbors = 1;
18031803
comp.confidence = sum;
18041804
ccv_array_push(seq[j], &comp);
@@ -1905,7 +1905,7 @@ static void _ccv_icf_detect_objects_with_multiscale_classifier_cascade(ccv_dense
19051905
{
19061906
ccv_comp_t comp;
19071907
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);
1908-
comp.id = j;
1908+
comp.id = j + 1;
19091909
comp.neighbors = 1;
19101910
comp.confidence = sum;
19111911
ccv_array_push(seq[j], &comp);
@@ -1987,31 +1987,55 @@ ccv_array_t* ccv_icf_detect_objects(ccv_dense_matrix_t* a, void* cascade, int co
19871987
ccv_array_push(seq2, comps + i);
19881988
}
19891989

1990+
// filter out large object rectangles contains small object rectangles
1991+
for(i = 0; i < seq2->rnum; i++)
1992+
{
1993+
ccv_comp_t* r2 = (ccv_comp_t*)ccv_array_get(seq2, i);
1994+
int distance = (int)(ccv_min(r2->rect.width, r2->rect.height) * 0.25 + 0.5);
1995+
for(j = 0; j < seq2->rnum; j++)
1996+
{
1997+
ccv_comp_t r1 = *(ccv_comp_t*)ccv_array_get(seq2, j);
1998+
if (i != j &&
1999+
abs(r1.id) == r2->id &&
2000+
r1.rect.x >= r2->rect.x - distance &&
2001+
r1.rect.y >= r2->rect.y - distance &&
2002+
r1.rect.x + r1.rect.width <= r2->rect.x + r2->rect.width + distance &&
2003+
r1.rect.y + r1.rect.height <= r2->rect.y + r2->rect.height + distance &&
2004+
// if r1 (the smaller one) is better, mute r2
2005+
(r2->confidence <= r1.confidence && r2->neighbors < r1.neighbors))
2006+
{
2007+
r2->id = -r2->id;
2008+
break;
2009+
}
2010+
}
2011+
}
2012+
19902013
// filter out small object rectangles inside large object rectangles
19912014
for(i = 0; i < seq2->rnum; i++)
19922015
{
1993-
ccv_root_comp_t r1 = *(ccv_root_comp_t*)ccv_array_get(seq2, i);
2016+
ccv_comp_t r1 = *(ccv_comp_t*)ccv_array_get(seq2, i);
19942017
int flag = 1;
19952018

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

20012024
if (i != j &&
2002-
r1.id == r2.id &&
2025+
abs(r1.id) == abs(r2.id) &&
20032026
r1.rect.x >= r2.rect.x - distance &&
20042027
r1.rect.y >= r2.rect.y - distance &&
20052028
r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance &&
20062029
r1.rect.y + r1.rect.height <= r2.rect.y + r2.rect.height + distance &&
2030+
// if r2 is better, we mute r1
20072031
(r2.confidence > r1.confidence || r2.neighbors >= r1.neighbors))
20082032
{
20092033
flag = 0;
20102034
break;
20112035
}
20122036
}
20132037

2014-
if(flag)
2038+
if(flag && r1->id > 0)
20152039
ccv_array_push(result_seq, &r1);
20162040
}
20172041
ccv_array_free(idx_seq);

0 commit comments

Comments
 (0)