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
fa09f3d1
Commit
fa09f3d1
authored
Apr 05, 2012
by
Alexey Spizhevoy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactored videostab module. Added MoreAccurateMotionWobbleSuppressor class
parent
f32b645b
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
163 additions
and
101 deletions
+163
-101
deblurring.hpp
modules/videostab/include/opencv2/videostab/deblurring.hpp
+6
-3
global_motion.hpp
...les/videostab/include/opencv2/videostab/global_motion.hpp
+19
-5
inpainting.hpp
modules/videostab/include/opencv2/videostab/inpainting.hpp
+6
-3
stabilizer.hpp
modules/videostab/include/opencv2/videostab/stabilizer.hpp
+2
-0
wobble_suppression.hpp
...ideostab/include/opencv2/videostab/wobble_suppression.hpp
+25
-9
global_motion.cpp
modules/videostab/src/global_motion.cpp
+35
-0
stabilizer.cpp
modules/videostab/src/stabilizer.cpp
+24
-7
wobble_suppression.cpp
modules/videostab/src/wobble_suppression.cpp
+23
-2
videostab.cpp
samples/cpp/videostab.cpp
+23
-72
No files found.
modules/videostab/include/opencv2/videostab/deblurring.hpp
View file @
fa09f3d1
...
...
@@ -56,13 +56,18 @@ CV_EXPORTS float calcBlurriness(const Mat &frame);
class
CV_EXPORTS
DeblurerBase
{
public
:
DeblurerBase
()
:
radius_
(
0
),
frames_
(
0
),
motions_
(
0
)
{}
DeblurerBase
()
:
radius_
(
0
),
frames_
(
0
),
motions_
(
0
)
,
blurrinessRates_
(
0
)
{}
virtual
~
DeblurerBase
()
{}
virtual
void
setRadius
(
int
val
)
{
radius_
=
val
;
}
virtual
int
radius
()
const
{
return
radius_
;
}
virtual
void
deblur
(
int
idx
,
Mat
&
frame
)
=
0
;
// data from stabilizer
virtual
void
setFrames
(
const
std
::
vector
<
Mat
>
&
val
)
{
frames_
=
&
val
;
}
virtual
const
std
::
vector
<
Mat
>&
frames
()
const
{
return
*
frames_
;
}
...
...
@@ -72,8 +77,6 @@ public:
virtual
void
setBlurrinessRates
(
const
std
::
vector
<
float
>
&
val
)
{
blurrinessRates_
=
&
val
;
}
virtual
const
std
::
vector
<
float
>&
blurrinessRates
()
const
{
return
*
blurrinessRates_
;
}
virtual
void
deblur
(
int
idx
,
Mat
&
frame
)
=
0
;
protected
:
int
radius_
;
const
std
::
vector
<
Mat
>
*
frames_
;
...
...
modules/videostab/include/opencv2/videostab/global_motion.hpp
View file @
fa09f3d1
...
...
@@ -44,6 +44,8 @@
#define __OPENCV_VIDEOSTAB_GLOBAL_MOTION_HPP__
#include <vector>
#include <string>
#include <fstream>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/videostab/optical_flow.hpp"
...
...
@@ -105,13 +107,25 @@ protected:
MotionModel
motionModel_
;
};
class
CV_EXPORTS
EyeMotionEstimato
r
:
public
GlobalMotionEstimatorBase
class
CV_EXPORTS
FromFileMotionReade
r
:
public
GlobalMotionEstimatorBase
{
public
:
virtual
Mat
estimate
(
const
Mat
&
/*frame0*/
,
const
Mat
&
/*frame1*/
)
{
return
Mat
::
eye
(
3
,
3
,
CV_32F
);
}
FromFileMotionReader
(
const
std
::
string
&
path
);
virtual
Mat
estimate
(
const
Mat
&
frame0
,
const
Mat
&
frame1
);
private
:
std
::
ifstream
file_
;
};
class
CV_EXPORTS
ToFileMotionWriter
:
public
GlobalMotionEstimatorBase
{
public
:
ToFileMotionWriter
(
const
std
::
string
&
path
,
Ptr
<
GlobalMotionEstimatorBase
>
estimator
);
virtual
Mat
estimate
(
const
Mat
&
frame0
,
const
Mat
&
frame1
);
private
:
std
::
ofstream
file_
;
Ptr
<
GlobalMotionEstimatorBase
>
estimator_
;
};
class
CV_EXPORTS
PyrLkRobustMotionEstimator
:
public
GlobalMotionEstimatorBase
...
...
modules/videostab/include/opencv2/videostab/inpainting.hpp
View file @
fa09f3d1
...
...
@@ -59,7 +59,7 @@ class CV_EXPORTS InpainterBase
{
public
:
InpainterBase
()
:
radius_
(
0
),
frames_
(
0
),
motions_
(
0
),
:
radius_
(
0
),
motionModel_
(
UNKNOWN
),
frames_
(
0
),
motions_
(
0
),
stabilizedFrames_
(
0
),
stabilizationMotions_
(
0
)
{}
virtual
~
InpainterBase
()
{}
...
...
@@ -70,6 +70,11 @@ public:
virtual
void
setMotionModel
(
MotionModel
val
)
{
motionModel_
=
val
;
}
virtual
MotionModel
motionModel
()
const
{
return
motionModel_
;
}
virtual
void
inpaint
(
int
idx
,
Mat
&
frame
,
Mat
&
mask
)
=
0
;
// data from stabilizer
virtual
void
setFrames
(
const
std
::
vector
<
Mat
>
&
val
)
{
frames_
=
&
val
;
}
virtual
const
std
::
vector
<
Mat
>&
frames
()
const
{
return
*
frames_
;
}
...
...
@@ -82,8 +87,6 @@ public:
virtual
void
setStabilizationMotions
(
const
std
::
vector
<
Mat
>
&
val
)
{
stabilizationMotions_
=
&
val
;
}
virtual
const
std
::
vector
<
Mat
>&
stabilizationMotions
()
const
{
return
*
stabilizationMotions_
;
}
virtual
void
inpaint
(
int
idx
,
Mat
&
frame
,
Mat
&
mask
)
=
0
;
protected
:
int
radius_
;
MotionModel
motionModel_
;
...
...
modules/videostab/include/opencv2/videostab/stabilizer.hpp
View file @
fa09f3d1
...
...
@@ -184,6 +184,8 @@ private:
int
frameCount_
;
bool
isPrePassDone_
;
bool
doWobbleSuppression_
;
std
::
vector
<
Mat
>
motions2_
;
Mat
suppressedFrame_
;
};
...
...
modules/videostab/include/opencv2/videostab/wobble_suppression.hpp
View file @
fa09f3d1
...
...
@@ -46,6 +46,7 @@
#include <vector>
#include "opencv2/core/core.hpp"
#include "opencv2/videostab/global_motion.hpp"
#include "opencv2/videostab/log.hpp"
namespace
cv
{
...
...
@@ -55,33 +56,48 @@ namespace videostab
class
CV_EXPORTS
WobbleSuppressorBase
{
public
:
WobbleSuppressorBase
();
virtual
~
WobbleSuppressorBase
()
{}
virtual
void
setFrames
(
const
std
::
vector
<
Mat
>
&
val
)
{
frames_
=
&
val
;
}
virtual
const
std
::
vector
<
Mat
>&
frames
()
const
{
return
*
frames_
;
}
void
setMotionEstimator
(
Ptr
<
GlobalMotionEstimatorBase
>
val
)
{
motionEstimator_
=
val
;
}
Ptr
<
GlobalMotionEstimatorBase
>
motionEstimator
()
const
{
return
motionEstimator_
;
}
virtual
void
suppress
(
int
idx
,
const
Mat
&
frame
,
Mat
&
result
)
=
0
;
// data from stabilizer
virtual
void
setFrameCount
(
int
val
)
{
frameCount_
=
val
;
}
virtual
int
frameCount
()
const
{
return
frameCount_
;
}
virtual
void
setMotions
(
const
std
::
vector
<
Mat
>
&
val
)
{
motions_
=
&
val
;
}
virtual
const
std
::
vector
<
Mat
>&
motions
()
const
{
return
*
motions_
;
}
virtual
void
set
StabilizedFrames
(
const
std
::
vector
<
Mat
>
&
val
)
{
stabilizedFrames
_
=
&
val
;
}
virtual
const
std
::
vector
<
Mat
>&
stabilizedFrames
()
const
{
return
*
stabilizedFrames
_
;
}
virtual
void
set
Motions2
(
const
std
::
vector
<
Mat
>
&
val
)
{
motions2
_
=
&
val
;
}
virtual
const
std
::
vector
<
Mat
>&
motions2
()
const
{
return
*
motions2
_
;
}
virtual
void
setStabilizationMotions
(
const
std
::
vector
<
Mat
>
&
val
)
{
stabilizationMotions_
=
&
val
;
}
virtual
const
std
::
vector
<
Mat
>&
stabilizationMotions
()
const
{
return
*
stabilizationMotions_
;
}
virtual
void
suppress
(
int
idx
,
Mat
&
frame
)
=
0
;
protected
:
const
std
::
vector
<
Mat
>
*
frames_
;
Ptr
<
GlobalMotionEstimatorBase
>
motionEstimator_
;
int
frameCount_
;
const
std
::
vector
<
Mat
>
*
motions_
;
const
std
::
vector
<
Mat
>
*
stabilizedFrames
_
;
const
std
::
vector
<
Mat
>
*
motions2
_
;
const
std
::
vector
<
Mat
>
*
stabilizationMotions_
;
};
class
CV_EXPORTS
NullWobbleSuppressor
:
public
WobbleSuppressorBase
{
public
:
virtual
void
suppress
(
int
idx
,
Mat
&
result
);
virtual
void
suppress
(
int
idx
,
const
Mat
&
frame
,
Mat
&
result
);
};
class
CV_EXPORTS
MoreAccurateMotionWobbleSuppressor
:
public
WobbleSuppressorBase
{
public
:
virtual
void
suppress
(
int
idx
,
const
Mat
&
frame
,
Mat
&
result
);
};
}
// namespace videostab
...
...
modules/videostab/src/global_motion.cpp
View file @
fa09f3d1
...
...
@@ -288,6 +288,41 @@ Mat estimateGlobalMotionRobust(
}
FromFileMotionReader
::
FromFileMotionReader
(
const
string
&
path
)
{
file_
.
open
(
path
.
c_str
());
CV_Assert
(
file_
.
is_open
());
}
Mat
FromFileMotionReader
::
estimate
(
const
Mat
&
/*frame0*/
,
const
Mat
&
/*frame1*/
)
{
Mat_
<
float
>
M
(
3
,
3
);
file_
>>
M
(
0
,
0
)
>>
M
(
0
,
1
)
>>
M
(
0
,
2
)
>>
M
(
1
,
0
)
>>
M
(
1
,
1
)
>>
M
(
1
,
2
)
>>
M
(
2
,
0
)
>>
M
(
2
,
1
)
>>
M
(
2
,
2
);
return
M
;
}
ToFileMotionWriter
::
ToFileMotionWriter
(
const
string
&
path
,
Ptr
<
GlobalMotionEstimatorBase
>
estimator
)
{
file_
.
open
(
path
.
c_str
());
CV_Assert
(
file_
.
is_open
());
estimator_
=
estimator
;
}
Mat
ToFileMotionWriter
::
estimate
(
const
Mat
&
frame0
,
const
Mat
&
frame1
)
{
Mat_
<
float
>
M
=
estimator_
->
estimate
(
frame0
,
frame1
);
file_
<<
M
(
0
,
0
)
<<
" "
<<
M
(
0
,
1
)
<<
" "
<<
M
(
0
,
2
)
<<
" "
<<
M
(
1
,
0
)
<<
" "
<<
M
(
1
,
1
)
<<
" "
<<
M
(
1
,
2
)
<<
" "
<<
M
(
2
,
0
)
<<
" "
<<
M
(
2
,
1
)
<<
" "
<<
M
(
2
,
2
)
<<
endl
;
return
M
;
}
PyrLkRobustMotionEstimator
::
PyrLkRobustMotionEstimator
()
:
ransacParams_
(
RansacParams
::
affine2dMotionStd
())
{
...
...
modules/videostab/src/stabilizer.cpp
View file @
fa09f3d1
...
...
@@ -53,7 +53,7 @@ namespace videostab
StabilizerBase
::
StabilizerBase
()
{
setLog
(
new
NullLog
());
setLog
(
new
LogToStdout
());
setFrameSource
(
new
NullFrameSource
());
setMotionEstimator
(
new
PyrLkRobustMotionEstimator
());
setDeblurer
(
new
NullDeblurer
());
...
...
@@ -304,6 +304,8 @@ void TwoPassStabilizer::reset()
StabilizerBase
::
reset
();
frameCount_
=
0
;
isPrePassDone_
=
false
;
doWobbleSuppression_
=
false
;
motions2_
.
clear
();
suppressedFrame_
=
Mat
();
}
...
...
@@ -333,10 +335,20 @@ void TwoPassStabilizer::runPrePassIfNecessary()
Mat
prevFrame
,
frame
;
WobbleSuppressorBase
*
wobbleSuppressor
=
static_cast
<
WobbleSuppressorBase
*>
(
wobbleSuppressor_
);
doWobbleSuppression_
=
dynamic_cast
<
NullWobbleSuppressor
*>
(
wobbleSuppressor
)
==
0
;
while
(
!
(
frame
=
frameSource_
->
nextFrame
()).
empty
())
{
if
(
frameCount_
>
0
)
{
motions_
.
push_back
(
motionEstimator_
->
estimate
(
prevFrame
,
frame
));
if
(
doWobbleSuppression_
)
{
motions2_
.
push_back
(
wobbleSuppressor_
->
motionEstimator
()
->
estimate
(
prevFrame
,
frame
));
}
}
else
{
frameSize_
=
frame
.
size
();
...
...
@@ -386,10 +398,15 @@ void TwoPassStabilizer::setUp(const Mat &firstFrame)
for
(
int
i
=
-
radius_
;
i
<=
0
;
++
i
)
at
(
i
,
frames_
)
=
firstFrame
;
wobbleSuppressor_
->
setFrames
(
frames_
);
wobbleSuppressor_
->
setMotions
(
motions_
);
wobbleSuppressor_
->
setStabilizedFrames
(
stabilizedFrames_
);
wobbleSuppressor_
->
setStabilizationMotions
(
stabilizationMotions_
);
WobbleSuppressorBase
*
wobbleSuppressor
=
static_cast
<
WobbleSuppressorBase
*>
(
wobbleSuppressor_
);
doWobbleSuppression_
=
dynamic_cast
<
NullWobbleSuppressor
*>
(
wobbleSuppressor
)
==
0
;
if
(
doWobbleSuppression_
)
{
wobbleSuppressor_
->
setFrameCount
(
frameCount_
);
wobbleSuppressor_
->
setMotions
(
motions_
);
wobbleSuppressor_
->
setMotions2
(
motions2_
);
wobbleSuppressor_
->
setStabilizationMotions
(
stabilizationMotions_
);
}
StabilizerBase
::
setUp
(
firstFrame
);
}
...
...
@@ -407,9 +424,9 @@ Mat TwoPassStabilizer::estimateStabilizationMotion()
}
Mat
TwoPassStabilizer
::
postProcessFrame
(
const
Mat
&
/*frame*/
)
Mat
TwoPassStabilizer
::
postProcessFrame
(
const
Mat
&
frame
)
{
wobbleSuppressor_
->
suppress
(
curStabilizedPos_
,
suppressedFrame_
);
wobbleSuppressor_
->
suppress
(
curStabilizedPos_
,
frame
,
suppressedFrame_
);
return
StabilizerBase
::
postProcessFrame
(
suppressedFrame_
);
}
...
...
modules/videostab/src/wobble_suppression.cpp
View file @
fa09f3d1
...
...
@@ -51,9 +51,30 @@ namespace cv
namespace
videostab
{
void
NullWobbleSuppressor
::
suppress
(
int
idx
,
Mat
&
result
)
WobbleSuppressorBase
::
WobbleSuppressorBase
()
:
motions_
(
0
),
stabilizationMotions_
(
0
)
{
result
=
at
(
idx
,
*
stabilizedFrames_
);
PyrLkRobustMotionEstimator
*
est
=
new
PyrLkRobustMotionEstimator
();
est
->
setMotionModel
(
HOMOGRAPHY
);
est
->
setRansacParams
(
RansacParams
::
homography2dMotionStd
());
setMotionEstimator
(
est
);
}
void
NullWobbleSuppressor
::
suppress
(
int
/*idx*/
,
const
Mat
&
frame
,
Mat
&
result
)
{
result
=
frame
;
}
void
MoreAccurateMotionWobbleSuppressor
::
suppress
(
int
idx
,
const
Mat
&
frame
,
Mat
&
result
)
{
CV_Assert
(
motions_
&&
stabilizationMotions_
);
// TODO implement
CV_Error
(
CV_StsNotImplemented
,
"MoreAccurateMotionWobbleSuppressor"
);
result
=
frame
;
}
}
// namespace videostab
...
...
samples/cpp/videostab.cpp
View file @
fa09f3d1
...
...
@@ -29,43 +29,6 @@ void run();
void
saveMotionsIfNecessary
();
void
printHelp
();
class
GlobalMotionReader
:
public
GlobalMotionEstimatorBase
{
public
:
GlobalMotionReader
(
string
path
)
{
ifstream
f
(
path
.
c_str
());
if
(
!
f
.
is_open
())
throw
runtime_error
(
"can't open motions file: "
+
path
);
int
size
;
f
>>
size
;
motions_
.
resize
(
size
);
for
(
int
i
=
0
;
i
<
size
;
++
i
)
{
Mat_
<
float
>
M
(
3
,
3
);
for
(
int
l
=
0
;
l
<
3
;
++
l
)
for
(
int
s
=
0
;
s
<
3
;
++
s
)
f
>>
M
(
l
,
s
);
motions_
[
i
]
=
M
;
}
pos_
=
0
;
}
virtual
Mat
estimate
(
const
Mat
&
/*frame0*/
,
const
Mat
&
/*frame1*/
)
{
if
(
pos_
>=
motions_
.
size
())
{
stringstream
text
;
text
<<
"can't load motion between frames "
<<
pos_
<<
" and "
<<
pos_
+
1
;
throw
runtime_error
(
text
.
str
());
}
return
motions_
[
pos_
++
];
}
private
:
vector
<
Mat
>
motions_
;
size_t
pos_
;
};
void
run
()
{
...
...
@@ -76,8 +39,6 @@ void run()
while
(
!
(
stabilizedFrame
=
stabilizedFrames
->
nextFrame
()).
empty
())
{
nframes
++
;
if
(
!
saveMotionsPath
.
empty
())
saveMotionsIfNecessary
();
if
(
!
outputPath
.
empty
())
{
if
(
!
writer
.
isOpened
())
...
...
@@ -99,33 +60,6 @@ void run()
}
void
saveMotionsIfNecessary
()
{
static
bool
areMotionsSaved
=
false
;
if
(
!
areMotionsSaved
)
{
IFrameSource
*
frameSource
=
static_cast
<
IFrameSource
*>
(
stabilizedFrames
);
TwoPassStabilizer
*
twoPassStabilizer
=
dynamic_cast
<
TwoPassStabilizer
*>
(
frameSource
);
if
(
twoPassStabilizer
)
{
ofstream
f
(
saveMotionsPath
.
c_str
());
const
vector
<
Mat
>
&
motions
=
twoPassStabilizer
->
motions
();
f
<<
motions
.
size
()
<<
endl
;
for
(
size_t
i
=
0
;
i
<
motions
.
size
();
++
i
)
{
Mat_
<
float
>
M
=
motions
[
i
];
for
(
int
l
=
0
,
k
=
0
;
l
<
3
;
++
l
)
for
(
int
s
=
0
;
s
<
3
;
++
s
,
++
k
)
f
<<
M
(
l
,
s
)
<<
" "
;
f
<<
endl
;
}
}
areMotionsSaved
=
true
;
cout
<<
"motions are saved"
;
}
}
void
printHelp
()
{
cout
<<
"OpenCV video stabilizer.
\n
"
...
...
@@ -173,6 +107,8 @@ void printHelp()
" --color-inpaint-radius=<float_number>
\n
"
" Set color inpainting radius (for ns and telea options only).
\n
"
" The default is 2.0
\n\n
"
" --wobble-suppress=(yes|no)
\n
"
" Perform wobble suppression. The default is no.
\n\n
"
" -o, --output=(no|<file_path>)
\n
"
" Set output file path explicitely. The default is stabilized.avi.
\n
"
" --fps=(<int_number>|auto)
\n
"
...
...
@@ -210,6 +146,7 @@ int main(int argc, const char **argv)
"{ | dist-thresh | 5.0 | }"
"{ | color-inpaint | no | }"
"{ | color-inpaint-radius | 2 | }"
"{ | wobble-suppress | no | }"
"{ o | output | stabilized.avi | }"
"{ | fps | auto | }"
"{ q | quiet | false | }"
...
...
@@ -226,7 +163,9 @@ int main(int argc, const char **argv)
StabilizerBase
*
stabilizer
;
bool
isTwoPass
=
arg
(
"est-trim"
)
==
"yes"
||
arg
(
"save-motions"
)
!=
"no"
;
bool
isTwoPass
=
arg
(
"est-trim"
)
==
"yes"
||
arg
(
"wobble-suppress"
)
==
"yes"
;
if
(
isTwoPass
)
{
TwoPassStabilizer
*
twoPassStabilizer
=
new
TwoPassStabilizer
();
...
...
@@ -236,6 +175,19 @@ int main(int argc, const char **argv)
twoPassStabilizer
->
setMotionStabilizer
(
new
GaussianMotionFilter
(
argi
(
"radius"
)));
else
twoPassStabilizer
->
setMotionStabilizer
(
new
GaussianMotionFilter
(
argi
(
"radius"
),
argf
(
"stdev"
)));
if
(
arg
(
"wobble-suppress"
)
==
"yes"
)
{
twoPassStabilizer
->
setWobbleSuppressor
(
new
MoreAccurateMotionWobbleSuppressor
());
if
(
arg
(
"load-motions"
)
!=
"no"
)
twoPassStabilizer
->
wobbleSuppressor
()
->
setMotionEstimator
(
new
FromFileMotionReader
(
"motions2."
+
arg
(
"load-motions"
)));
if
(
arg
(
"save-motions"
)
!=
"no"
)
{
Ptr
<
GlobalMotionEstimatorBase
>
est
=
twoPassStabilizer
->
wobbleSuppressor
()
->
motionEstimator
();
twoPassStabilizer
->
wobbleSuppressor
()
->
setMotionEstimator
(
new
ToFileMotionWriter
(
"motions2."
+
arg
(
"save-motions"
),
est
));
}
}
}
else
{
...
...
@@ -289,10 +241,11 @@ int main(int argc, const char **argv)
stabilizer
->
setMotionEstimator
(
est_
);
}
else
stabilizer
->
setMotionEstimator
(
new
GlobalMotionReader
(
arg
(
"load-motions"
)));
stabilizer
->
setMotionEstimator
(
new
FromFileMotionReader
(
"motions."
+
arg
(
"load-motions"
)));
if
(
arg
(
"save-motions"
)
!=
"no"
)
saveMotionsPath
=
arg
(
"save-motions"
);
stabilizer
->
setMotionEstimator
(
new
ToFileMotionWriter
(
"motions."
+
arg
(
"save-motions"
),
stabilizer
->
motionEstimator
()));
stabilizer
->
setRadius
(
argi
(
"radius"
));
if
(
arg
(
"deblur"
)
==
"yes"
)
...
...
@@ -342,9 +295,7 @@ int main(int argc, const char **argv)
{
inpainters
->
setRadius
(
argi
(
"radius"
));
stabilizer
->
setInpainter
(
inpainters_
);
}
stabilizer
->
setLog
(
new
LogToStdout
());
}
if
(
arg
(
"output"
)
!=
"no"
)
outputPath
=
arg
(
"output"
);
...
...
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