Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
wjd2002
Ncnn
提交
8e94566f
N
Ncnn
项目概览
wjd2002
/
Ncnn
11 个月 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
N
Ncnn
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
8e94566f
编写于
12月 04, 2020
作者:
N
nihuini
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
add nanodet example
上级
25b22447
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
417 addition
and
0 deletion
+417
-0
examples/CMakeLists.txt
examples/CMakeLists.txt
+1
-0
examples/nanodet.cpp
examples/nanodet.cpp
+416
-0
未找到文件。
examples/CMakeLists.txt
浏览文件 @
8e94566f
...
...
@@ -51,4 +51,5 @@ else()
ncnn_add_example
(
simplepose
)
ncnn_add_example
(
retinaface
)
ncnn_add_example
(
yolact
)
ncnn_add_example
(
nanodet
)
endif
()
examples/nanodet.cpp
0 → 100644
浏览文件 @
8e94566f
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#include "net.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <stdlib.h>
#include <float.h>
#include <stdio.h>
#include <vector>
struct
Object
{
cv
::
Rect_
<
float
>
rect
;
int
label
;
float
prob
;
};
static
inline
float
intersection_area
(
const
Object
&
a
,
const
Object
&
b
)
{
cv
::
Rect_
<
float
>
inter
=
a
.
rect
&
b
.
rect
;
return
inter
.
area
();
}
static
void
qsort_descent_inplace
(
std
::
vector
<
Object
>&
faceobjects
,
int
left
,
int
right
)
{
int
i
=
left
;
int
j
=
right
;
float
p
=
faceobjects
[(
left
+
right
)
/
2
].
prob
;
while
(
i
<=
j
)
{
while
(
faceobjects
[
i
].
prob
>
p
)
i
++
;
while
(
faceobjects
[
j
].
prob
<
p
)
j
--
;
if
(
i
<=
j
)
{
// swap
std
::
swap
(
faceobjects
[
i
],
faceobjects
[
j
]);
i
++
;
j
--
;
}
}
#pragma omp parallel sections
{
#pragma omp section
{
if
(
left
<
j
)
qsort_descent_inplace
(
faceobjects
,
left
,
j
);
}
#pragma omp section
{
if
(
i
<
right
)
qsort_descent_inplace
(
faceobjects
,
i
,
right
);
}
}
}
static
void
qsort_descent_inplace
(
std
::
vector
<
Object
>&
faceobjects
)
{
if
(
faceobjects
.
empty
())
return
;
qsort_descent_inplace
(
faceobjects
,
0
,
faceobjects
.
size
()
-
1
);
}
static
void
nms_sorted_bboxes
(
const
std
::
vector
<
Object
>&
faceobjects
,
std
::
vector
<
int
>&
picked
,
float
nms_threshold
)
{
picked
.
clear
();
const
int
n
=
faceobjects
.
size
();
std
::
vector
<
float
>
areas
(
n
);
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
areas
[
i
]
=
faceobjects
[
i
].
rect
.
width
*
faceobjects
[
i
].
rect
.
height
;
}
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
const
Object
&
a
=
faceobjects
[
i
];
int
keep
=
1
;
for
(
int
j
=
0
;
j
<
(
int
)
picked
.
size
();
j
++
)
{
const
Object
&
b
=
faceobjects
[
picked
[
j
]];
// intersection over union
float
inter_area
=
intersection_area
(
a
,
b
);
float
union_area
=
areas
[
i
]
+
areas
[
picked
[
j
]]
-
inter_area
;
// float IoU = inter_area / union_area
if
(
inter_area
/
union_area
>
nms_threshold
)
keep
=
0
;
}
if
(
keep
)
picked
.
push_back
(
i
);
}
}
static
void
generate_proposals
(
const
ncnn
::
Mat
&
cls_pred
,
const
ncnn
::
Mat
&
dis_pred
,
int
stride
,
const
ncnn
::
Mat
&
in_pad
,
float
prob_threshold
,
std
::
vector
<
Object
>&
objects
)
{
const
int
num_grid
=
cls_pred
.
h
;
int
num_grid_x
;
int
num_grid_y
;
if
(
in_pad
.
w
>
in_pad
.
h
)
{
num_grid_x
=
in_pad
.
w
/
stride
;
num_grid_y
=
num_grid
/
num_grid_x
;
}
else
{
num_grid_y
=
in_pad
.
h
/
stride
;
num_grid_x
=
num_grid
/
num_grid_y
;
}
const
int
num_class
=
cls_pred
.
w
;
const
int
reg_max_1
=
dis_pred
.
w
/
4
;
for
(
int
i
=
0
;
i
<
num_grid_y
;
i
++
)
{
for
(
int
j
=
0
;
j
<
num_grid_x
;
j
++
)
{
const
int
idx
=
i
*
num_grid_x
+
j
;
const
float
*
scores
=
cls_pred
.
row
(
idx
);
// find label with max score
int
label
=
-
1
;
float
score
=
-
FLT_MAX
;
for
(
int
k
=
0
;
k
<
num_class
;
k
++
)
{
if
(
scores
[
k
]
>
score
)
{
label
=
k
;
score
=
scores
[
k
];
}
}
if
(
score
>=
prob_threshold
)
{
ncnn
::
Mat
bbox_pred
(
reg_max_1
,
4
,
(
void
*
)
dis_pred
.
row
(
idx
));
{
ncnn
::
Layer
*
softmax
=
ncnn
::
create_layer
(
"Softmax"
);
ncnn
::
ParamDict
pd
;
pd
.
set
(
0
,
1
);
// axis
pd
.
set
(
1
,
1
);
softmax
->
load_param
(
pd
);
ncnn
::
Option
opt
;
opt
.
num_threads
=
1
;
opt
.
use_packing_layout
=
false
;
softmax
->
create_pipeline
(
opt
);
softmax
->
forward_inplace
(
bbox_pred
,
opt
);
softmax
->
destroy_pipeline
(
opt
);
delete
softmax
;
}
float
dis_pred
[
4
];
for
(
int
k
=
0
;
k
<
4
;
k
++
)
{
float
dis
=
0.
f
;
const
float
*
dis_after_sm
=
bbox_pred
.
row
(
k
);
for
(
int
l
=
0
;
l
<
reg_max_1
;
l
++
)
{
dis
+=
l
*
dis_after_sm
[
l
];
}
dis_pred
[
k
]
=
dis
*
stride
;
}
float
pb_cx
=
(
j
+
0.5
f
)
*
stride
;
float
pb_cy
=
(
i
+
0.5
f
)
*
stride
;
float
x0
=
pb_cx
-
dis_pred
[
0
];
float
y0
=
pb_cy
-
dis_pred
[
1
];
float
x1
=
pb_cx
+
dis_pred
[
2
];
float
y1
=
pb_cy
+
dis_pred
[
3
];
Object
obj
;
obj
.
rect
.
x
=
x0
;
obj
.
rect
.
y
=
y0
;
obj
.
rect
.
width
=
x1
-
x0
;
obj
.
rect
.
height
=
y1
-
y0
;
obj
.
label
=
label
;
obj
.
prob
=
score
;
objects
.
push_back
(
obj
);
}
}
}
}
static
int
detect_nanodet
(
const
cv
::
Mat
&
bgr
,
std
::
vector
<
Object
>&
objects
)
{
ncnn
::
Net
nanodet
;
nanodet
.
opt
.
use_vulkan_compute
=
true
;
// nanodet.opt.use_bf16_storage = true;
// original pretrained model from https://github.com/RangiLyu/nanodet
// the ncnn model https://github.com/nihui/ncnn-assets/tree/master/models
nanodet
.
load_param
(
"nanodet_m.param"
);
nanodet
.
load_model
(
"nanodet_m.bin"
);
int
width
=
bgr
.
cols
;
int
height
=
bgr
.
rows
;
const
int
target_size
=
320
;
const
float
prob_threshold
=
0.4
f
;
const
float
nms_threshold
=
0.5
f
;
// pad to multiple of 32
int
w
=
width
;
int
h
=
height
;
float
scale
=
1.
f
;
if
(
w
>
h
)
{
scale
=
(
float
)
target_size
/
w
;
w
=
target_size
;
h
=
h
*
scale
;
}
else
{
scale
=
(
float
)
target_size
/
h
;
h
=
target_size
;
w
=
w
*
scale
;
}
ncnn
::
Mat
in
=
ncnn
::
Mat
::
from_pixels_resize
(
bgr
.
data
,
ncnn
::
Mat
::
PIXEL_BGR
,
width
,
height
,
w
,
h
);
// pad to target_size rectangle
int
wpad
=
(
w
+
31
)
/
32
*
32
-
w
;
int
hpad
=
(
h
+
31
)
/
32
*
32
-
h
;
ncnn
::
Mat
in_pad
;
ncnn
::
copy_make_border
(
in
,
in_pad
,
hpad
/
2
,
hpad
-
hpad
/
2
,
wpad
/
2
,
wpad
-
wpad
/
2
,
ncnn
::
BORDER_CONSTANT
,
0.
f
);
const
float
mean_vals
[
3
]
=
{
103.53
f
,
116.28
f
,
123.675
f
};
const
float
norm_vals
[
3
]
=
{
0.017429
f
,
0.017507
f
,
0.017125
f
};
in_pad
.
substract_mean_normalize
(
mean_vals
,
norm_vals
);
ncnn
::
Extractor
ex
=
nanodet
.
create_extractor
();
ex
.
input
(
"input.1"
,
in_pad
);
std
::
vector
<
Object
>
proposals
;
// stride 8
{
ncnn
::
Mat
cls_pred
;
ncnn
::
Mat
dis_pred
;
ex
.
extract
(
"792"
,
cls_pred
);
ex
.
extract
(
"795"
,
dis_pred
);
std
::
vector
<
Object
>
objects8
;
generate_proposals
(
cls_pred
,
dis_pred
,
8
,
in_pad
,
prob_threshold
,
objects8
);
proposals
.
insert
(
proposals
.
end
(),
objects8
.
begin
(),
objects8
.
end
());
}
// stride 16
{
ncnn
::
Mat
cls_pred
;
ncnn
::
Mat
dis_pred
;
ex
.
extract
(
"814"
,
cls_pred
);
ex
.
extract
(
"817"
,
dis_pred
);
std
::
vector
<
Object
>
objects16
;
generate_proposals
(
cls_pred
,
dis_pred
,
16
,
in_pad
,
prob_threshold
,
objects16
);
proposals
.
insert
(
proposals
.
end
(),
objects16
.
begin
(),
objects16
.
end
());
}
// stride 32
{
ncnn
::
Mat
cls_pred
;
ncnn
::
Mat
dis_pred
;
ex
.
extract
(
"836"
,
cls_pred
);
ex
.
extract
(
"839"
,
dis_pred
);
std
::
vector
<
Object
>
objects32
;
generate_proposals
(
cls_pred
,
dis_pred
,
32
,
in_pad
,
prob_threshold
,
objects32
);
proposals
.
insert
(
proposals
.
end
(),
objects32
.
begin
(),
objects32
.
end
());
}
// sort all proposals by score from highest to lowest
qsort_descent_inplace
(
proposals
);
// apply nms with nms_threshold
std
::
vector
<
int
>
picked
;
nms_sorted_bboxes
(
proposals
,
picked
,
nms_threshold
);
int
count
=
picked
.
size
();
objects
.
resize
(
count
);
for
(
int
i
=
0
;
i
<
count
;
i
++
)
{
objects
[
i
]
=
proposals
[
picked
[
i
]];
// adjust offset to original unpadded
float
x0
=
(
objects
[
i
].
rect
.
x
-
(
wpad
/
2
))
/
scale
;
float
y0
=
(
objects
[
i
].
rect
.
y
-
(
hpad
/
2
))
/
scale
;
float
x1
=
(
objects
[
i
].
rect
.
x
+
objects
[
i
].
rect
.
width
-
(
wpad
/
2
))
/
scale
;
float
y1
=
(
objects
[
i
].
rect
.
y
+
objects
[
i
].
rect
.
height
-
(
hpad
/
2
))
/
scale
;
// clip
x0
=
std
::
max
(
std
::
min
(
x0
,
(
float
)(
width
-
1
)),
0.
f
);
y0
=
std
::
max
(
std
::
min
(
y0
,
(
float
)(
height
-
1
)),
0.
f
);
x1
=
std
::
max
(
std
::
min
(
x1
,
(
float
)(
width
-
1
)),
0.
f
);
y1
=
std
::
max
(
std
::
min
(
y1
,
(
float
)(
height
-
1
)),
0.
f
);
objects
[
i
].
rect
.
x
=
x0
;
objects
[
i
].
rect
.
y
=
y0
;
objects
[
i
].
rect
.
width
=
x1
-
x0
;
objects
[
i
].
rect
.
height
=
y1
-
y0
;
}
return
0
;
}
static
void
draw_objects
(
const
cv
::
Mat
&
bgr
,
const
std
::
vector
<
Object
>&
objects
)
{
static
const
char
*
class_names
[]
=
{
"person"
,
"bicycle"
,
"car"
,
"motorcycle"
,
"airplane"
,
"bus"
,
"train"
,
"truck"
,
"boat"
,
"traffic light"
,
"fire hydrant"
,
"stop sign"
,
"parking meter"
,
"bench"
,
"bird"
,
"cat"
,
"dog"
,
"horse"
,
"sheep"
,
"cow"
,
"elephant"
,
"bear"
,
"zebra"
,
"giraffe"
,
"backpack"
,
"umbrella"
,
"handbag"
,
"tie"
,
"suitcase"
,
"frisbee"
,
"skis"
,
"snowboard"
,
"sports ball"
,
"kite"
,
"baseball bat"
,
"baseball glove"
,
"skateboard"
,
"surfboard"
,
"tennis racket"
,
"bottle"
,
"wine glass"
,
"cup"
,
"fork"
,
"knife"
,
"spoon"
,
"bowl"
,
"banana"
,
"apple"
,
"sandwich"
,
"orange"
,
"broccoli"
,
"carrot"
,
"hot dog"
,
"pizza"
,
"donut"
,
"cake"
,
"chair"
,
"couch"
,
"potted plant"
,
"bed"
,
"dining table"
,
"toilet"
,
"tv"
,
"laptop"
,
"mouse"
,
"remote"
,
"keyboard"
,
"cell phone"
,
"microwave"
,
"oven"
,
"toaster"
,
"sink"
,
"refrigerator"
,
"book"
,
"clock"
,
"vase"
,
"scissors"
,
"teddy bear"
,
"hair drier"
,
"toothbrush"
};
cv
::
Mat
image
=
bgr
.
clone
();
for
(
size_t
i
=
0
;
i
<
objects
.
size
();
i
++
)
{
const
Object
&
obj
=
objects
[
i
];
fprintf
(
stderr
,
"%d = %.5f at %.2f %.2f %.2f x %.2f
\n
"
,
obj
.
label
,
obj
.
prob
,
obj
.
rect
.
x
,
obj
.
rect
.
y
,
obj
.
rect
.
width
,
obj
.
rect
.
height
);
cv
::
rectangle
(
image
,
obj
.
rect
,
cv
::
Scalar
(
255
,
0
,
0
));
char
text
[
256
];
sprintf
(
text
,
"%s %.1f%%"
,
class_names
[
obj
.
label
],
obj
.
prob
*
100
);
int
baseLine
=
0
;
cv
::
Size
label_size
=
cv
::
getTextSize
(
text
,
cv
::
FONT_HERSHEY_SIMPLEX
,
0.5
,
1
,
&
baseLine
);
int
x
=
obj
.
rect
.
x
;
int
y
=
obj
.
rect
.
y
-
label_size
.
height
-
baseLine
;
if
(
y
<
0
)
y
=
0
;
if
(
x
+
label_size
.
width
>
image
.
cols
)
x
=
image
.
cols
-
label_size
.
width
;
cv
::
rectangle
(
image
,
cv
::
Rect
(
cv
::
Point
(
x
,
y
),
cv
::
Size
(
label_size
.
width
,
label_size
.
height
+
baseLine
)),
cv
::
Scalar
(
255
,
255
,
255
),
-
1
);
cv
::
putText
(
image
,
text
,
cv
::
Point
(
x
,
y
+
label_size
.
height
),
cv
::
FONT_HERSHEY_SIMPLEX
,
0.5
,
cv
::
Scalar
(
0
,
0
,
0
));
}
cv
::
imshow
(
"image"
,
image
);
cv
::
waitKey
(
0
);
}
int
main
(
int
argc
,
char
**
argv
)
{
if
(
argc
!=
2
)
{
fprintf
(
stderr
,
"Usage: %s [imagepath]
\n
"
,
argv
[
0
]);
return
-
1
;
}
const
char
*
imagepath
=
argv
[
1
];
cv
::
Mat
m
=
cv
::
imread
(
imagepath
,
1
);
if
(
m
.
empty
())
{
fprintf
(
stderr
,
"cv::imread %s failed
\n
"
,
imagepath
);
return
-
1
;
}
std
::
vector
<
Object
>
objects
;
detect_nanodet
(
m
,
objects
);
draw_objects
(
m
,
objects
);
return
0
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录