Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
4ba8b531
Commit
4ba8b531
authored
Jan 29, 2013
by
marina.kolpakova
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
split public interface and realization for SoftCascadeOctave
parent
f3227c3f
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
92 additions
and
55 deletions
+92
-55
fpool.cpp
apps/sft/fpool.cpp
+2
-0
sft.cpp
apps/sft/sft.cpp
+8
-5
softcascade.hpp
...s/softcascade/include/opencv2/softcascade/softcascade.hpp
+9
-36
precomp.hpp
modules/softcascade/src/precomp.hpp
+1
-0
soft_cascade_octave.cpp
modules/softcascade/src/soft_cascade_octave.cpp
+72
-14
No files found.
apps/sft/fpool.cpp
View file @
4ba8b531
...
@@ -43,6 +43,8 @@
...
@@ -43,6 +43,8 @@
#include <sft/fpool.hpp>
#include <sft/fpool.hpp>
#include <sft/random.hpp>
#include <sft/random.hpp>
#include <iostream>
#include <queue>
#include <queue>
// ========= FeaturePool ========= //
// ========= FeaturePool ========= //
...
...
apps/sft/sft.cpp
View file @
4ba8b531
...
@@ -43,6 +43,7 @@
...
@@ -43,6 +43,7 @@
// Trating application for Soft Cascades.
// Trating application for Soft Cascades.
#include <sft/common.hpp>
#include <sft/common.hpp>
#include <iostream>
#include <sft/fpool.hpp>
#include <sft/fpool.hpp>
#include <sft/config.hpp>
#include <sft/config.hpp>
...
@@ -127,22 +128,24 @@ int main(int argc, char** argv)
...
@@ -127,22 +128,24 @@ int main(int argc, char** argv)
cv
::
Rect
boundingBox
=
cfg
.
bbox
(
it
);
cv
::
Rect
boundingBox
=
cfg
.
bbox
(
it
);
std
::
cout
<<
"Object bounding box"
<<
boundingBox
<<
std
::
endl
;
std
::
cout
<<
"Object bounding box"
<<
boundingBox
<<
std
::
endl
;
cv
::
SoftCascadeOctave
boost
(
boundingBox
,
npositives
,
nnegatives
,
*
it
,
shrinkage
);
typedef
cv
::
SoftCascadeOctave
Octave
;
cv
::
Ptr
<
Octave
>
boost
=
Octave
::
create
(
boundingBox
,
npositives
,
nnegatives
,
*
it
,
shrinkage
);
std
::
string
path
=
cfg
.
trainPath
;
std
::
string
path
=
cfg
.
trainPath
;
sft
::
ScaledDataset
dataset
(
path
,
*
it
);
sft
::
ScaledDataset
dataset
(
path
,
*
it
);
if
(
boost
.
train
(
&
dataset
,
&
pool
,
cfg
.
weaks
,
cfg
.
treeDepth
))
if
(
boost
->
train
(
&
dataset
,
&
pool
,
cfg
.
weaks
,
cfg
.
treeDepth
))
{
{
CvFileStorage
*
fout
=
cvOpenFileStorage
(
cfg
.
resPath
(
it
).
c_str
(),
0
,
CV_STORAGE_WRITE
);
CvFileStorage
*
fout
=
cvOpenFileStorage
(
cfg
.
resPath
(
it
).
c_str
(),
0
,
CV_STORAGE_WRITE
);
boost
.
write
(
fout
,
cfg
.
cascadeName
);
boost
->
write
(
fout
,
cfg
.
cascadeName
);
cvReleaseFileStorage
(
&
fout
);
cvReleaseFileStorage
(
&
fout
);
cv
::
Mat
thresholds
;
cv
::
Mat
thresholds
;
boost
.
setRejectThresholds
(
thresholds
);
boost
->
setRejectThresholds
(
thresholds
);
boost
.
write
(
fso
,
&
pool
,
thresholds
);
boost
->
write
(
fso
,
&
pool
,
thresholds
);
cv
::
FileStorage
tfs
((
"thresholds."
+
cfg
.
resPath
(
it
)).
c_str
(),
cv
::
FileStorage
::
WRITE
);
cv
::
FileStorage
tfs
((
"thresholds."
+
cfg
.
resPath
(
it
)).
c_str
(),
cv
::
FileStorage
::
WRITE
);
tfs
<<
"thresholds"
<<
thresholds
;
tfs
<<
"thresholds"
<<
thresholds
;
...
...
modules/softcascade/include/opencv2/softcascade/softcascade.hpp
View file @
4ba8b531
...
@@ -44,7 +44,6 @@
...
@@ -44,7 +44,6 @@
#define __OPENCV_SOFTCASCADE_HPP__
#define __OPENCV_SOFTCASCADE_HPP__
#include "opencv2/core/core.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/ml/ml.hpp"
namespace
cv
{
namespace
cv
{
...
@@ -90,7 +89,7 @@ public:
...
@@ -90,7 +89,7 @@ public:
// ========================================================================== //
// ========================================================================== //
//
Implementation of
Integral Channel Feature.
//
Public Interface for
Integral Channel Feature.
// ========================================================================== //
// ========================================================================== //
class
CV_EXPORTS_W
ChannelFeatureBuilder
:
public
Algorithm
class
CV_EXPORTS_W
ChannelFeatureBuilder
:
public
Algorithm
...
@@ -155,12 +154,11 @@ private:
...
@@ -155,12 +154,11 @@ private:
};
};
// ========================================================================== //
// ========================================================================== //
//
Implementation of
singe soft (stageless) cascade octave training.
//
Public Interface for
singe soft (stageless) cascade octave training.
// ========================================================================== //
// ========================================================================== //
class
CV_EXPORTS
SoftCascadeOctave
:
public
cv
::
Boost
class
CV_EXPORTS
SoftCascadeOctave
:
public
Algorithm
{
{
public
:
public
:
enum
enum
{
{
// Direct backward pruning. (Cha Zhang and Paul Viola)
// Direct backward pruning. (Cha Zhang and Paul Viola)
...
@@ -171,39 +169,14 @@ public:
...
@@ -171,39 +169,14 @@ public:
HEURISTIC
=
4
HEURISTIC
=
4
};
};
SoftCascadeOctave
(
cv
::
Rect
boundingBox
,
int
npositives
,
int
nnegatives
,
int
logScale
,
int
shrinkage
);
virtual
bool
train
(
const
Dataset
*
dataset
,
const
FeaturePool
*
pool
,
int
weaks
,
int
treeDepth
);
virtual
void
setRejectThresholds
(
OutputArray
thresholds
);
virtual
void
write
(
CvFileStorage
*
fs
,
string
name
)
const
;
virtual
void
write
(
cv
::
FileStorage
&
fs
,
const
FeaturePool
*
pool
,
InputArray
thresholds
)
const
;
virtual
float
predict
(
InputArray
_sample
,
InputArray
_votes
,
bool
raw_mode
,
bool
return_sum
)
const
;
virtual
~
SoftCascadeOctave
();
virtual
~
SoftCascadeOctave
();
protected
:
static
cv
::
Ptr
<
SoftCascadeOctave
>
create
(
cv
::
Rect
boundingBox
,
int
npositives
,
int
nnegatives
,
virtual
bool
train
(
const
cv
::
Mat
&
trainData
,
const
cv
::
Mat
&
responses
,
const
cv
::
Mat
&
varIdx
=
cv
::
Mat
(),
int
logScale
,
int
shrinkage
);
const
cv
::
Mat
&
sampleIdx
=
cv
::
Mat
(),
const
cv
::
Mat
&
varType
=
cv
::
Mat
(),
const
cv
::
Mat
&
missingDataMask
=
cv
::
Mat
());
void
processPositives
(
const
Dataset
*
dataset
,
const
FeaturePool
*
pool
);
void
generateNegatives
(
const
Dataset
*
dataset
,
const
FeaturePool
*
pool
);
float
predict
(
const
Mat
&
_sample
,
const
cv
::
Range
range
)
const
;
private
:
void
traverse
(
const
CvBoostTree
*
tree
,
cv
::
FileStorage
&
fs
,
int
&
nfeatures
,
int
*
used
,
const
double
*
th
)
const
;
virtual
void
initial_weights
(
double
(
&
p
)[
2
]);
int
logScale
;
cv
::
Rect
boundingBox
;
int
npositives
;
int
nnegatives
;
int
shrinkage
;
Mat
integrals
;
Mat
responses
;
CvBoostParams
params
;
Mat
trainData
;
virtual
bool
train
(
const
Dataset
*
dataset
,
const
FeaturePool
*
pool
,
int
weaks
,
int
treeDepth
)
=
0
;
virtual
void
setRejectThresholds
(
OutputArray
thresholds
)
=
0
;
virtual
void
write
(
cv
::
FileStorage
&
fs
,
const
FeaturePool
*
pool
,
InputArray
thresholds
)
const
=
0
;
virtual
void
write
(
CvFileStorage
*
fs
,
string
name
)
const
=
0
;
};
};
CV_EXPORTS
bool
initModule_softcascade
(
void
);
CV_EXPORTS
bool
initModule_softcascade
(
void
);
...
...
modules/softcascade/src/precomp.hpp
View file @
4ba8b531
...
@@ -52,6 +52,7 @@
...
@@ -52,6 +52,7 @@
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/core/core_c.h"
#include "opencv2/core/core_c.h"
#include "opencv2/core/internal.hpp"
#include "opencv2/core/internal.hpp"
#include "opencv2/ml/ml.hpp"
#include "opencv2/opencv_modules.hpp"
#include "opencv2/opencv_modules.hpp"
...
...
modules/softcascade/src/soft_cascade_octave.cpp
View file @
4ba8b531
...
@@ -42,6 +42,7 @@
...
@@ -42,6 +42,7 @@
#include "precomp.hpp"
#include "precomp.hpp"
#include <queue>
#include <queue>
#include <string>
#define WITH_DEBUG_OUT
#define WITH_DEBUG_OUT
...
@@ -122,10 +123,56 @@ struct Random
...
@@ -122,10 +123,56 @@ struct Random
}
}
#endif
#endif
using
cv
::
Dataset
;
using
cv
::
FeaturePool
;
using
cv
::
InputArray
;
using
cv
::
OutputArray
;
using
cv
::
Mat
;
cv
::
FeaturePool
::~
FeaturePool
(){}
cv
::
FeaturePool
::~
FeaturePool
(){}
cv
::
Dataset
::~
Dataset
(){}
cv
::
Dataset
::~
Dataset
(){}
cv
::
SoftCascadeOctave
::
SoftCascadeOctave
(
cv
::
Rect
bb
,
int
np
,
int
nn
,
int
ls
,
int
shr
)
class
BoostedSoftCascadeOctave
:
public
cv
::
Boost
,
public
cv
::
SoftCascadeOctave
{
public
:
BoostedSoftCascadeOctave
(
cv
::
Rect
boundingBox
=
cv
::
Rect
(),
int
npositives
=
0
,
int
nnegatives
=
0
,
int
logScale
=
0
,
int
shrinkage
=
1
);
virtual
~
BoostedSoftCascadeOctave
();
virtual
cv
::
AlgorithmInfo
*
info
()
const
;
virtual
bool
train
(
const
Dataset
*
dataset
,
const
FeaturePool
*
pool
,
int
weaks
,
int
treeDepth
);
virtual
void
setRejectThresholds
(
OutputArray
thresholds
);
virtual
void
write
(
cv
::
FileStorage
&
fs
,
const
FeaturePool
*
pool
,
InputArray
thresholds
)
const
;
virtual
void
write
(
CvFileStorage
*
fs
,
std
::
string
name
)
const
;
protected
:
virtual
float
predict
(
InputArray
_sample
,
InputArray
_votes
,
bool
raw_mode
,
bool
return_sum
)
const
;
virtual
bool
train
(
const
cv
::
Mat
&
trainData
,
const
cv
::
Mat
&
responses
,
const
cv
::
Mat
&
varIdx
=
cv
::
Mat
(),
const
cv
::
Mat
&
sampleIdx
=
cv
::
Mat
(),
const
cv
::
Mat
&
varType
=
cv
::
Mat
(),
const
cv
::
Mat
&
missingDataMask
=
cv
::
Mat
());
void
processPositives
(
const
Dataset
*
dataset
,
const
FeaturePool
*
pool
);
void
generateNegatives
(
const
Dataset
*
dataset
,
const
FeaturePool
*
pool
);
float
predict
(
const
Mat
&
_sample
,
const
cv
::
Range
range
)
const
;
private
:
void
traverse
(
const
CvBoostTree
*
tree
,
cv
::
FileStorage
&
fs
,
int
&
nfeatures
,
int
*
used
,
const
double
*
th
)
const
;
virtual
void
initial_weights
(
double
(
&
p
)[
2
]);
int
logScale
;
cv
::
Rect
boundingBox
;
int
npositives
;
int
nnegatives
;
int
shrinkage
;
Mat
integrals
;
Mat
responses
;
CvBoostParams
params
;
Mat
trainData
;
};
BoostedSoftCascadeOctave
::
BoostedSoftCascadeOctave
(
cv
::
Rect
bb
,
int
np
,
int
nn
,
int
ls
,
int
shr
)
:
logScale
(
ls
),
boundingBox
(
bb
),
npositives
(
np
),
nnegatives
(
nn
),
shrinkage
(
shr
)
:
logScale
(
ls
),
boundingBox
(
bb
),
npositives
(
np
),
nnegatives
(
nn
),
shrinkage
(
shr
)
{
{
int
maxSample
=
npositives
+
nnegatives
;
int
maxSample
=
npositives
+
nnegatives
;
...
@@ -155,9 +202,9 @@ cv::SoftCascadeOctave::SoftCascadeOctave(cv::Rect bb, int np, int nn, int ls, in
...
@@ -155,9 +202,9 @@ cv::SoftCascadeOctave::SoftCascadeOctave(cv::Rect bb, int np, int nn, int ls, in
params
=
_params
;
params
=
_params
;
}
}
cv
::
SoftCascadeOctave
::~
SoftCascadeOctave
(){}
BoostedSoftCascadeOctave
::~
Boosted
SoftCascadeOctave
(){}
bool
cv
::
SoftCascadeOctave
::
train
(
const
cv
::
Mat
&
_trainData
,
const
cv
::
Mat
&
_responses
,
const
cv
::
Mat
&
varIdx
,
bool
Boosted
SoftCascadeOctave
::
train
(
const
cv
::
Mat
&
_trainData
,
const
cv
::
Mat
&
_responses
,
const
cv
::
Mat
&
varIdx
,
const
cv
::
Mat
&
sampleIdx
,
const
cv
::
Mat
&
varType
,
const
cv
::
Mat
&
missingDataMask
)
const
cv
::
Mat
&
sampleIdx
,
const
cv
::
Mat
&
varType
,
const
cv
::
Mat
&
missingDataMask
)
{
{
bool
update
=
false
;
bool
update
=
false
;
...
@@ -165,7 +212,7 @@ bool cv::SoftCascadeOctave::train( const cv::Mat& _trainData, const cv::Mat& _re
...
@@ -165,7 +212,7 @@ bool cv::SoftCascadeOctave::train( const cv::Mat& _trainData, const cv::Mat& _re
update
);
update
);
}
}
void
cv
::
SoftCascadeOctave
::
setRejectThresholds
(
cv
::
OutputArray
_thresholds
)
void
Boosted
SoftCascadeOctave
::
setRejectThresholds
(
cv
::
OutputArray
_thresholds
)
{
{
dprintf
(
"set thresholds according to DBP strategy
\n
"
);
dprintf
(
"set thresholds according to DBP strategy
\n
"
);
...
@@ -212,7 +259,7 @@ void cv::SoftCascadeOctave::setRejectThresholds(cv::OutputArray _thresholds)
...
@@ -212,7 +259,7 @@ void cv::SoftCascadeOctave::setRejectThresholds(cv::OutputArray _thresholds)
}
}
}
}
void
cv
::
SoftCascadeOctave
::
processPositives
(
const
Dataset
*
dataset
,
const
FeaturePool
*
pool
)
void
Boosted
SoftCascadeOctave
::
processPositives
(
const
Dataset
*
dataset
,
const
FeaturePool
*
pool
)
{
{
int
w
=
boundingBox
.
width
;
int
w
=
boundingBox
.
width
;
int
h
=
boundingBox
.
height
;
int
h
=
boundingBox
.
height
;
...
@@ -259,7 +306,7 @@ void cv::SoftCascadeOctave::processPositives(const Dataset* dataset, const Featu
...
@@ -259,7 +306,7 @@ void cv::SoftCascadeOctave::processPositives(const Dataset* dataset, const Featu
#undef USE_LONG_SEEDS
#undef USE_LONG_SEEDS
void
cv
::
SoftCascadeOctave
::
generateNegatives
(
const
Dataset
*
dataset
,
const
FeaturePool
*
pool
)
void
Boosted
SoftCascadeOctave
::
generateNegatives
(
const
Dataset
*
dataset
,
const
FeaturePool
*
pool
)
{
{
// ToDo: set seed, use offsets
// ToDo: set seed, use offsets
sft
::
Random
::
engine
eng
(
DX_DY_SEED
);
sft
::
Random
::
engine
eng
(
DX_DY_SEED
);
...
@@ -308,7 +355,7 @@ template <typename T> int sgn(T val) {
...
@@ -308,7 +355,7 @@ template <typename T> int sgn(T val) {
return
(
T
(
0
)
<
val
)
-
(
val
<
T
(
0
));
return
(
T
(
0
)
<
val
)
-
(
val
<
T
(
0
));
}
}
void
cv
::
SoftCascadeOctave
::
traverse
(
const
CvBoostTree
*
tree
,
cv
::
FileStorage
&
fs
,
int
&
nfeatures
,
int
*
used
,
const
double
*
th
)
const
void
Boosted
SoftCascadeOctave
::
traverse
(
const
CvBoostTree
*
tree
,
cv
::
FileStorage
&
fs
,
int
&
nfeatures
,
int
*
used
,
const
double
*
th
)
const
{
{
std
::
queue
<
const
CvDTreeNode
*>
nodes
;
std
::
queue
<
const
CvDTreeNode
*>
nodes
;
nodes
.
push
(
tree
->
get_root
());
nodes
.
push
(
tree
->
get_root
());
...
@@ -365,7 +412,7 @@ void cv::SoftCascadeOctave::traverse(const CvBoostTree* tree, cv::FileStorage& f
...
@@ -365,7 +412,7 @@ void cv::SoftCascadeOctave::traverse(const CvBoostTree* tree, cv::FileStorage& f
fs
<<
"}"
;
fs
<<
"}"
;
}
}
void
cv
::
SoftCascadeOctave
::
write
(
cv
::
FileStorage
&
fso
,
const
FeaturePool
*
pool
,
InputArray
_thresholds
)
const
void
Boosted
SoftCascadeOctave
::
write
(
cv
::
FileStorage
&
fso
,
const
FeaturePool
*
pool
,
InputArray
_thresholds
)
const
{
{
CV_Assert
(
!
_thresholds
.
empty
());
CV_Assert
(
!
_thresholds
.
empty
());
cv
::
Mat
used
(
1
,
weak
->
total
*
(
(
int
)
pow
(
2.
f
,
params
.
max_depth
)
-
1
),
CV_32SC1
);
cv
::
Mat
used
(
1
,
weak
->
total
*
(
(
int
)
pow
(
2.
f
,
params
.
max_depth
)
-
1
),
CV_32SC1
);
...
@@ -397,14 +444,14 @@ void cv::SoftCascadeOctave::write( cv::FileStorage &fso, const FeaturePool* pool
...
@@ -397,14 +444,14 @@ void cv::SoftCascadeOctave::write( cv::FileStorage &fso, const FeaturePool* pool
<<
"}"
;
<<
"}"
;
}
}
void
cv
::
SoftCascadeOctave
::
initial_weights
(
double
(
&
p
)[
2
])
void
Boosted
SoftCascadeOctave
::
initial_weights
(
double
(
&
p
)[
2
])
{
{
double
n
=
data
->
sample_count
;
double
n
=
data
->
sample_count
;
p
[
0
]
=
n
/
(
2.
*
(
double
)(
nnegatives
));
p
[
0
]
=
n
/
(
2.
*
(
double
)(
nnegatives
));
p
[
1
]
=
n
/
(
2.
*
(
double
)(
npositives
));
p
[
1
]
=
n
/
(
2.
*
(
double
)(
npositives
));
}
}
bool
cv
::
SoftCascadeOctave
::
train
(
const
Dataset
*
dataset
,
const
FeaturePool
*
pool
,
int
weaks
,
int
treeDepth
)
bool
Boosted
SoftCascadeOctave
::
train
(
const
Dataset
*
dataset
,
const
FeaturePool
*
pool
,
int
weaks
,
int
treeDepth
)
{
{
CV_Assert
(
treeDepth
==
2
);
CV_Assert
(
treeDepth
==
2
);
CV_Assert
(
weaks
>
0
);
CV_Assert
(
weaks
>
0
);
...
@@ -458,7 +505,7 @@ bool cv::SoftCascadeOctave::train(const Dataset* dataset, const FeaturePool* poo
...
@@ -458,7 +505,7 @@ bool cv::SoftCascadeOctave::train(const Dataset* dataset, const FeaturePool* poo
}
}
float
cv
::
SoftCascadeOctave
::
predict
(
cv
::
InputArray
_sample
,
cv
::
InputArray
_votes
,
bool
raw_mode
,
bool
return_sum
)
const
float
Boosted
SoftCascadeOctave
::
predict
(
cv
::
InputArray
_sample
,
cv
::
InputArray
_votes
,
bool
raw_mode
,
bool
return_sum
)
const
{
{
cv
::
Mat
sample
=
_sample
.
getMat
();
cv
::
Mat
sample
=
_sample
.
getMat
();
CvMat
csample
=
sample
;
CvMat
csample
=
sample
;
...
@@ -472,13 +519,24 @@ float cv::SoftCascadeOctave::predict( cv::InputArray _sample, cv::InputArray _vo
...
@@ -472,13 +519,24 @@ float cv::SoftCascadeOctave::predict( cv::InputArray _sample, cv::InputArray _vo
}
}
}
}
float
cv
::
SoftCascadeOctave
::
predict
(
const
Mat
&
_sample
,
const
cv
::
Range
range
)
const
float
Boosted
SoftCascadeOctave
::
predict
(
const
Mat
&
_sample
,
const
cv
::
Range
range
)
const
{
{
CvMat
sample
=
_sample
;
CvMat
sample
=
_sample
;
return
CvBoost
::
predict
(
&
sample
,
0
,
0
,
range
,
false
,
true
);
return
CvBoost
::
predict
(
&
sample
,
0
,
0
,
range
,
false
,
true
);
}
}
void
cv
::
SoftCascadeOctave
::
write
(
CvFileStorage
*
fs
,
string
name
)
const
void
BoostedSoftCascadeOctave
::
write
(
CvFileStorage
*
fs
,
std
::
string
_name
)
const
{
CvBoost
::
write
(
fs
,
_name
.
c_str
());
}
CV_INIT_ALGORITHM
(
BoostedSoftCascadeOctave
,
"SoftCascadeOctave.BoostedSoftCascadeOctave"
,
);
cv
::
SoftCascadeOctave
::~
SoftCascadeOctave
(){}
cv
::
Ptr
<
cv
::
SoftCascadeOctave
>
cv
::
SoftCascadeOctave
::
create
(
cv
::
Rect
boundingBox
,
int
npositives
,
int
nnegatives
,
int
logScale
,
int
shrinkage
)
{
{
CvBoost
::
write
(
fs
,
name
.
c_str
());
cv
::
Ptr
<
cv
::
SoftCascadeOctave
>
octave
(
new
BoostedSoftCascadeOctave
(
boundingBox
,
npositives
,
nnegatives
,
logScale
,
shrinkage
));
return
octave
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment