Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Opencv
提交
8fa8b36b
O
Opencv
项目概览
Greenplum
/
Opencv
11 个月 前同步成功
通知
7
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
O
Opencv
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
8fa8b36b
编写于
12月 10, 2013
作者:
I
Ilya Lavrenov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
added cv::Laplacian, cv::Sobel, cv::Scharr, cv::GaussianBlur to T-API
上级
d802b4d1
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
176 addition
and
45 deletion
+176
-45
modules/imgproc/src/deriv.cpp
modules/imgproc/src/deriv.cpp
+27
-20
modules/imgproc/src/smooth.cpp
modules/imgproc/src/smooth.cpp
+27
-17
modules/imgproc/test/ocl/test_filters.cpp
modules/imgproc/test/ocl/test_filters.cpp
+121
-7
modules/ts/include/opencv2/ts/ocl_test.hpp
modules/ts/include/opencv2/ts/ocl_test.hpp
+1
-1
未找到文件。
modules/imgproc/src/deriv.cpp
浏览文件 @
8fa8b36b
...
...
@@ -413,15 +413,15 @@ static bool IPPDeriv(const Mat& src, Mat& dst, int ddepth, int dx, int dy, int k
void
cv
::
Sobel
(
InputArray
_src
,
OutputArray
_dst
,
int
ddepth
,
int
dx
,
int
dy
,
int
ksize
,
double
scale
,
double
delta
,
int
borderType
)
{
Mat
src
=
_src
.
getMat
(
);
int
stype
=
_src
.
type
(),
sdepth
=
CV_MAT_DEPTH
(
stype
),
cn
=
CV_MAT_CN
(
stype
);
if
(
ddepth
<
0
)
ddepth
=
src
.
depth
();
_dst
.
create
(
src
.
size
(),
CV_MAKETYPE
(
ddepth
,
src
.
channels
())
);
Mat
dst
=
_dst
.
getMat
();
ddepth
=
sdepth
;
_dst
.
create
(
_src
.
size
(),
CV_MAKETYPE
(
ddepth
,
cn
)
);
#ifdef HAVE_TEGRA_OPTIMIZATION
if
(
scale
==
1.0
&&
delta
==
0
)
{
Mat
src
=
_src
.
getMat
(),
dst
=
_dst
.
getMat
();
if
(
ksize
==
3
&&
tegra
::
sobel3x3
(
src
,
dst
,
dx
,
dy
,
borderType
))
return
;
if
(
ksize
==
-
1
&&
tegra
::
scharr
(
src
,
dst
,
dx
,
dy
,
borderType
))
...
...
@@ -430,13 +430,14 @@ void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
#endif
#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
if
(
dx
<
3
&&
dy
<
3
&&
src
.
channels
()
==
1
&&
borderType
==
1
)
if
(
dx
<
3
&&
dy
<
3
&&
cn
==
1
&&
borderType
==
BORDER_REPLICATE
)
{
Mat
src
=
_src
.
getMat
(),
dst
=
_dst
.
getMat
();
if
(
IPPDeriv
(
src
,
dst
,
ddepth
,
dx
,
dy
,
ksize
,
scale
))
return
;
}
#endif
int
ktype
=
std
::
max
(
CV_32F
,
std
::
max
(
ddepth
,
s
rc
.
depth
()
));
int
ktype
=
std
::
max
(
CV_32F
,
std
::
max
(
ddepth
,
s
depth
));
Mat
kx
,
ky
;
getDerivKernels
(
kx
,
ky
,
dx
,
dy
,
ksize
,
false
,
ktype
);
...
...
@@ -449,33 +450,36 @@ void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
else
ky
*=
scale
;
}
sepFilter2D
(
src
,
dst
,
ddepth
,
kx
,
ky
,
Point
(
-
1
,
-
1
),
delta
,
borderType
);
sepFilter2D
(
_src
,
_dst
,
ddepth
,
kx
,
ky
,
Point
(
-
1
,
-
1
),
delta
,
borderType
);
}
void
cv
::
Scharr
(
InputArray
_src
,
OutputArray
_dst
,
int
ddepth
,
int
dx
,
int
dy
,
double
scale
,
double
delta
,
int
borderType
)
{
Mat
src
=
_src
.
getMat
(
);
int
stype
=
_src
.
type
(),
sdepth
=
CV_MAT_DEPTH
(
stype
),
cn
=
CV_MAT_CN
(
stype
);
if
(
ddepth
<
0
)
ddepth
=
src
.
depth
();
_dst
.
create
(
src
.
size
(),
CV_MAKETYPE
(
ddepth
,
src
.
channels
())
);
Mat
dst
=
_dst
.
getMat
();
ddepth
=
sdepth
;
_dst
.
create
(
_src
.
size
(),
CV_MAKETYPE
(
ddepth
,
cn
)
);
#ifdef HAVE_TEGRA_OPTIMIZATION
if
(
scale
==
1.0
&&
delta
==
0
)
{
Mat
src
=
_src
.
getMat
(),
dst
=
_dst
.
getMat
();
if
(
tegra
::
scharr
(
src
,
dst
,
dx
,
dy
,
borderType
))
return
;
}
#endif
#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
if
(
dx
<
2
&&
dy
<
2
&&
src
.
channels
()
==
1
&&
borderType
==
1
)
{
Mat
src
=
_src
.
getMat
(),
dst
=
_dst
.
getMat
();
if
(
IPPDerivScharr
(
src
,
dst
,
ddepth
,
dx
,
dy
,
scale
))
return
;
}
#endif
int
ktype
=
std
::
max
(
CV_32F
,
std
::
max
(
ddepth
,
s
rc
.
depth
()
));
int
ktype
=
std
::
max
(
CV_32F
,
std
::
max
(
ddepth
,
s
depth
));
Mat
kx
,
ky
;
getScharrKernels
(
kx
,
ky
,
dx
,
dy
,
false
,
ktype
);
...
...
@@ -488,22 +492,22 @@ void cv::Scharr( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
else
ky
*=
scale
;
}
sepFilter2D
(
src
,
dst
,
ddepth
,
kx
,
ky
,
Point
(
-
1
,
-
1
),
delta
,
borderType
);
sepFilter2D
(
_src
,
_dst
,
ddepth
,
kx
,
ky
,
Point
(
-
1
,
-
1
),
delta
,
borderType
);
}
void
cv
::
Laplacian
(
InputArray
_src
,
OutputArray
_dst
,
int
ddepth
,
int
ksize
,
double
scale
,
double
delta
,
int
borderType
)
{
Mat
src
=
_src
.
getMat
(
);
int
stype
=
_src
.
type
(),
sdepth
=
CV_MAT_DEPTH
(
stype
),
cn
=
CV_MAT_CN
(
stype
);
if
(
ddepth
<
0
)
ddepth
=
src
.
depth
();
_dst
.
create
(
src
.
size
(),
CV_MAKETYPE
(
ddepth
,
src
.
channels
())
);
Mat
dst
=
_dst
.
getMat
();
ddepth
=
sdepth
;
_dst
.
create
(
_src
.
size
(),
CV_MAKETYPE
(
ddepth
,
cn
)
);
#ifdef HAVE_TEGRA_OPTIMIZATION
if
(
scale
==
1.0
&&
delta
==
0
)
{
Mat
src
=
_src
.
getMat
(),
dst
=
_dst
.
getMat
();
if
(
ksize
==
1
&&
tegra
::
laplace1
(
src
,
dst
,
borderType
))
return
;
if
(
ksize
==
3
&&
tegra
::
laplace3
(
src
,
dst
,
borderType
))
...
...
@@ -516,15 +520,18 @@ void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize,
if
(
ksize
==
1
||
ksize
==
3
)
{
float
K
[
2
][
9
]
=
{{
0
,
1
,
0
,
1
,
-
4
,
1
,
0
,
1
,
0
},
{
2
,
0
,
2
,
0
,
-
8
,
0
,
2
,
0
,
2
}};
{
{
0
,
1
,
0
,
1
,
-
4
,
1
,
0
,
1
,
0
},
{
2
,
0
,
2
,
0
,
-
8
,
0
,
2
,
0
,
2
}
};
Mat
kernel
(
3
,
3
,
CV_32F
,
K
[
ksize
==
3
]);
if
(
scale
!=
1
)
kernel
*=
scale
;
filter2D
(
src
,
dst
,
ddepth
,
kernel
,
Point
(
-
1
,
-
1
),
delta
,
borderType
);
filter2D
(
_src
,
_dst
,
ddepth
,
kernel
,
Point
(
-
1
,
-
1
),
delta
,
borderType
);
}
else
{
Mat
src
=
_src
.
getMat
(),
dst
=
_dst
.
getMat
();
const
size_t
STRIPE_SIZE
=
1
<<
14
;
int
depth
=
src
.
depth
();
...
...
modules/imgproc/src/smooth.cpp
浏览文件 @
8fa8b36b
...
...
@@ -798,10 +798,10 @@ cv::Mat cv::getGaussianKernel( int n, double sigma, int ktype )
return
kernel
;
}
namespace
cv
{
cv
::
Ptr
<
cv
::
FilterEngine
>
cv
::
createGaussianFilter
(
int
type
,
Size
ksize
,
double
sigma1
,
double
sigma2
,
int
borderType
)
static
void
createGaussianKernels
(
Mat
&
kx
,
Mat
&
ky
,
int
type
,
Size
ksize
,
double
sigma1
,
double
sigma2
)
{
int
depth
=
CV_MAT_DEPTH
(
type
);
if
(
sigma2
<=
0
)
...
...
@@ -819,12 +819,21 @@ cv::Ptr<cv::FilterEngine> cv::createGaussianFilter( int type, Size ksize,
sigma1
=
std
::
max
(
sigma1
,
0.
);
sigma2
=
std
::
max
(
sigma2
,
0.
);
Mat
kx
=
getGaussianKernel
(
ksize
.
width
,
sigma1
,
std
::
max
(
depth
,
CV_32F
)
);
Mat
ky
;
kx
=
getGaussianKernel
(
ksize
.
width
,
sigma1
,
std
::
max
(
depth
,
CV_32F
)
);
if
(
ksize
.
height
==
ksize
.
width
&&
std
::
abs
(
sigma1
-
sigma2
)
<
DBL_EPSILON
)
ky
=
kx
;
else
ky
=
getGaussianKernel
(
ksize
.
height
,
sigma2
,
std
::
max
(
depth
,
CV_32F
)
);
}
}
cv
::
Ptr
<
cv
::
FilterEngine
>
cv
::
createGaussianFilter
(
int
type
,
Size
ksize
,
double
sigma1
,
double
sigma2
,
int
borderType
)
{
Mat
kx
,
ky
;
createGaussianKernels
(
kx
,
ky
,
type
,
ksize
,
sigma1
,
sigma2
);
return
createSeparableLinearFilter
(
type
,
type
,
kx
,
ky
,
Point
(
-
1
,
-
1
),
0
,
borderType
);
}
...
...
@@ -834,33 +843,34 @@ void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize,
double
sigma1
,
double
sigma2
,
int
borderType
)
{
Mat
src
=
_src
.
getMat
();
_dst
.
create
(
src
.
size
(),
src
.
type
()
);
Mat
dst
=
_dst
.
getMat
(
);
int
type
=
_src
.
type
();
Size
size
=
_src
.
size
(
);
_dst
.
create
(
size
,
type
);
if
(
borderType
!=
BORDER_CONSTANT
)
{
if
(
s
rc
.
rows
==
1
)
if
(
s
ize
.
height
==
1
)
ksize
.
height
=
1
;
if
(
s
rc
.
cols
==
1
)
if
(
s
ize
.
width
==
1
)
ksize
.
width
=
1
;
}
if
(
ksize
.
width
==
1
&&
ksize
.
height
==
1
)
{
src
.
copyTo
(
dst
);
_src
.
copyTo
(
_
dst
);
return
;
}
#ifdef HAVE_TEGRA_OPTIMIZATION
if
(
sigma1
==
0
&&
sigma2
==
0
&&
tegra
::
gaussian
(
src
,
dst
,
ksize
,
borderType
))
if
(
sigma1
==
0
&&
sigma2
==
0
&&
tegra
::
gaussian
(
_src
.
getMat
(),
_dst
.
getMat
()
,
ksize
,
borderType
))
return
;
#endif
#if defined HAVE_IPP && (IPP_VERSION_MAJOR >= 7)
if
(
src
.
type
()
==
CV_32FC1
&&
sigma1
==
sigma2
&&
ksize
.
width
==
ksize
.
height
&&
sigma1
!=
0.0
)
if
(
type
==
CV_32FC1
&&
sigma1
==
sigma2
&&
ksize
.
width
==
ksize
.
height
&&
sigma1
!=
0.0
)
{
IppiSize
roi
=
{
src
.
cols
,
src
.
rows
};
Mat
src
=
_src
.
getMat
(),
dst
=
_dst
.
getMat
();
IppiSize
roi
=
{
src
.
cols
,
src
.
rows
};
int
bufSize
=
0
;
ippiFilterGaussGetBufferSize_32f_C1R
(
roi
,
ksize
.
width
,
&
bufSize
);
AutoBuffer
<
uchar
>
buf
(
bufSize
+
128
);
...
...
@@ -873,11 +883,11 @@ void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize,
}
#endif
Ptr
<
FilterEngine
>
f
=
createGaussianFilter
(
src
.
type
(),
ksize
,
sigma1
,
sigma2
,
borderType
);
f
->
apply
(
src
,
dst
);
Mat
kx
,
ky
;
createGaussianKernels
(
kx
,
ky
,
type
,
ksize
,
sigma1
,
sigma2
);
sepFilter2D
(
_src
,
_dst
,
CV_MAT_DEPTH
(
type
),
kx
,
ky
,
Point
(
-
1
,
-
1
),
0
,
borderType
);
}
/****************************************************************************************\
Median Filter
\****************************************************************************************/
...
...
modules/imgproc/test/ocl/test_filters.cpp
浏览文件 @
8fa8b36b
...
...
@@ -60,7 +60,7 @@ namespace ocl {
PARAM_TEST_CASE
(
FilterTestBase
,
MatType
,
int
,
// kernel size
Size
,
// dx, dy
int
,
// border type
BorderType
,
// border type
double
,
// optional parameter
bool
)
// roi or not
{
...
...
@@ -145,32 +145,146 @@ OCL_TEST_P(Bilateral, Mat)
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Laplacian
typedef
FilterTestBase
LaplacianTest
;
OCL_TEST_P
(
LaplacianTest
,
Accuracy
)
{
double
scale
=
param
;
for
(
int
j
=
0
;
j
<
test_loop_times
;
j
++
)
{
random_roi
();
OCL_OFF
(
cv
::
Laplacian
(
src_roi
,
dst_roi
,
-
1
,
ksize
,
scale
,
0
,
borderType
));
OCL_ON
(
cv
::
Laplacian
(
usrc_roi
,
udst_roi
,
-
1
,
ksize
,
scale
,
0
,
borderType
));
Near
();
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Sobel
typedef
FilterTestBase
SobelTest
;
OCL_TEST_P
(
SobelTest
,
Mat
)
{
int
dx
=
size
.
width
,
dy
=
size
.
height
;
double
scale
=
param
;
for
(
int
j
=
0
;
j
<
test_loop_times
;
j
++
)
{
random_roi
();
OCL_OFF
(
cv
::
Sobel
(
src_roi
,
dst_roi
,
-
1
,
dx
,
dy
,
ksize
,
scale
,
/* delta */
0
,
borderType
));
OCL_ON
(
cv
::
Sobel
(
usrc_roi
,
udst_roi
,
-
1
,
dx
,
dy
,
ksize
,
scale
,
/* delta */
0
,
borderType
));
Near
();
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Scharr
typedef
FilterTestBase
ScharrTest
;
OCL_TEST_P
(
ScharrTest
,
Mat
)
{
int
dx
=
size
.
width
,
dy
=
size
.
height
;
double
scale
=
param
;
for
(
int
j
=
0
;
j
<
test_loop_times
;
j
++
)
{
random_roi
();
OCL_OFF
(
cv
::
Scharr
(
src_roi
,
dst_roi
,
-
1
,
dx
,
dy
,
scale
,
/* delta */
0
,
borderType
));
OCL_ON
(
cv
::
Scharr
(
usrc_roi
,
udst_roi
,
-
1
,
dx
,
dy
,
scale
,
/* delta */
0
,
borderType
));
Near
();
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// GaussianBlur
typedef
FilterTestBase
GaussianBlurTest
;
OCL_TEST_P
(
GaussianBlurTest
,
Mat
)
{
for
(
int
j
=
0
;
j
<
test_loop_times
;
j
++
)
{
random_roi
();
double
sigma1
=
rng
.
uniform
(
0.1
,
1.0
);
double
sigma2
=
rng
.
uniform
(
0.1
,
1.0
);
OCL_OFF
(
cv
::
GaussianBlur
(
src_roi
,
dst_roi
,
Size
(
ksize
,
ksize
),
sigma1
,
sigma2
,
borderType
));
OCL_ON
(
cv
::
GaussianBlur
(
usrc_roi
,
udst_roi
,
Size
(
ksize
,
ksize
),
sigma1
,
sigma2
,
borderType
));
Near
(
CV_MAT_DEPTH
(
type
)
==
CV_8U
?
3
:
5e-5
,
false
);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define FILTER_BORDER_SET_NO_ISOLATED \
Values((
int)BORDER_CONSTANT, (int)BORDER_REPLICATE, (int)BORDER_REFLECT, (int)BORDER_WRAP, (int
)BORDER_REFLECT_101
/*, \
Values((
BorderType)BORDER_CONSTANT, (BorderType)BORDER_REPLICATE, (BorderType)BORDER_REFLECT, (BorderType)BORDER_WRAP, (BorderType
)BORDER_REFLECT_101
/*, \
(int)BORDER_CONSTANT|BORDER_ISOLATED, (int)BORDER_REPLICATE|BORDER_ISOLATED, \
(int)BORDER_REFLECT|BORDER_ISOLATED, (int)BORDER_WRAP|BORDER_ISOLATED, \
(int)BORDER_REFLECT_101|BORDER_ISOLATED*/
) // WRAP and ISOLATED are not supported by cv:: version
#define FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED \
Values((
int)BORDER_CONSTANT, (int)BORDER_REPLICATE, (int)BORDER_REFLECT,
/*(int)BORDER_WRAP,*/
(int
)BORDER_REFLECT_101
/*, \
Values((
BorderType)BORDER_CONSTANT, (BorderType)BORDER_REPLICATE, (BorderType)BORDER_REFLECT,
/*(int)BORDER_WRAP,*/
(BorderType
)BORDER_REFLECT_101
/*, \
(int)BORDER_CONSTANT|BORDER_ISOLATED, (int)BORDER_REPLICATE|BORDER_ISOLATED, \
(int)BORDER_REFLECT|BORDER_ISOLATED, (int)BORDER_WRAP|BORDER_ISOLATED, \
(int)BORDER_REFLECT_101|BORDER_ISOLATED*/
) // WRAP and ISOLATED are not supported by cv:: version
#define FILTER_DATATYPES Values(CV_8UC1, CV_8UC2, CV_8UC3, CV_8UC4, \
CV_32FC1, CV_32FC3, CV_32FC4, \
CV_64FC1, CV_64FC3, CV_64FC4)
#define FILTER_TYPES Values(CV_8UC1, CV_8UC2, CV_8UC4, CV_32FC1, CV_32FC4, CV_64FC1, CV_64FC4)
OCL_INSTANTIATE_TEST_CASE_P
(
Filter
,
Bilateral
,
Combine
(
Values
((
MatType
)
CV_8UC1
),
Values
(
5
,
9
),
Values
(
5
,
9
),
// kernel size
Values
(
Size
(
0
,
0
)),
// not used
FILTER_BORDER_SET_NO_ISOLATED
,
Values
(
0.0
),
// not used
Bool
()));
OCL_INSTANTIATE_TEST_CASE_P
(
Filter
,
LaplacianTest
,
Combine
(
FILTER_TYPES
,
Values
(
1
,
3
),
// kernel size
Values
(
Size
(
0
,
0
)),
// not used
FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED
,
Values
(
1.0
,
0.2
,
3.0
),
// kernel scale
Bool
()));
OCL_INSTANTIATE_TEST_CASE_P
(
Filter
,
SobelTest
,
Combine
(
FILTER_TYPES
,
Values
(
3
,
5
),
// kernel size
Values
(
Size
(
1
,
0
),
Size
(
1
,
1
),
Size
(
2
,
0
),
Size
(
2
,
1
)),
// dx, dy
FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED
,
Values
(
0.0
),
// not used
Bool
()));
OCL_INSTANTIATE_TEST_CASE_P
(
Filter
,
ScharrTest
,
Combine
(
FILTER_TYPES
,
Values
(
0
),
// not used
Values
(
Size
(
0
,
1
),
Size
(
1
,
0
)),
// dx, dy
FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED
,
Values
(
1.0
,
0.2
),
// kernel scale
Bool
()));
OCL_INSTANTIATE_TEST_CASE_P
(
Filter
,
GaussianBlurTest
,
Combine
(
FILTER_TYPES
,
Values
(
3
,
5
),
// kernel size
Values
(
Size
(
0
,
0
)),
// not used
FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED
,
Values
(
0.0
),
// not used
Bool
()));
}
}
// namespace cvtest::ocl
#endif // HAVE_OPENCL
modules/ts/include/opencv2/ts/ocl_test.hpp
浏览文件 @
8fa8b36b
...
...
@@ -307,7 +307,7 @@ IMPLEMENT_PARAM_CLASS(Channels, int)
CV_ENUM
(
Interpolation
,
INTER_NEAREST
,
INTER_LINEAR
,
INTER_CUBIC
,
INTER_AREA
)
CV_ENUM
(
ThreshOp
,
THRESH_BINARY
,
THRESH_BINARY_INV
,
THRESH_TRUNC
,
THRESH_TOZERO
,
THRESH_TOZERO_INV
)
CV_ENUM
(
BorderType
,
BORDER_REPLICATE
,
BORDER_REFLECT
,
BORDER_WRAP
,
BORDER_REFLECT_101
)
CV_ENUM
(
BorderType
,
BORDER_
CONSTANT
,
BORDER_
REPLICATE
,
BORDER_REFLECT
,
BORDER_WRAP
,
BORDER_REFLECT_101
)
#define OCL_INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
INSTANTIATE_TEST_CASE_P(OCL_ ## prefix, test_case_name, generator)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录