$ mkdir Github && cd Github
$ git clone https://github.com/ultralytics/ultralytics
$ cd ultralytics
$ git checkout b9b0fd8bf409c822b7fcb21d65722b242f5307fc
$ pip install -r requirements.txt
forward
method of class C2f(nn.Module):
def forward(self, x):
# """Forward pass through C2f layer."""
# y = list(self.cv1(x).chunk(2, 1))
# y.extend(m(y[-1]) for m in self.m)
# return self.cv2(torch.cat(y, 1))
# !< https://github.com/FeiGeChuanShu/ncnn-android-yolov8
x = self.cv1(x)
x = [x, x[:, self.c:, ...]]
x.extend(m(x[-1]) for m in self.m)
x.pop(1)
return self.cv2(torch.cat(x, 1))
forward
method of class Detect(nn.Module):
def forward(self, x):
"""Concatenates and returns predicted bounding boxes and class probabilities."""
shape = x[0].shape # BCHW
for i in range(self.nl):
x[i] = torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1)
if self.training:
return x
elif self.dynamic or self.shape != shape:
self.anchors, self.strides = (x.transpose(0, 1) for x in make_anchors(x, self.stride, 0.5))
self.shape = shape
x_cat = torch.cat([xi.view(shape[0], self.no, -1) for xi in x], 2)
return x_cat
# if self.export and self.format in ('saved_model', 'pb', 'tflite', 'edgetpu', 'tfjs'): # avoid TF FlexSplitV ops
# box = x_cat[:, :self.reg_max * 4]
# cls = x_cat[:, self.reg_max * 4:]
# else:
# box, cls = x_cat.split((self.reg_max * 4, self.nc), 1)
# dbox = dist2bbox(self.dfl(box), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides
# if self.export and self.format in ('tflite', 'edgetpu'):
# # Normalize xywh with image size to mitigate quantization error of TFLite integer models as done in YOLOv5:
# # https://github.com/ultralytics/yolov5/blob/0c8de3fca4a702f8ff5c435e67f378d1fce70243/models/tf.py#L307-L309
# # See this PR for details: https://github.com/ultralytics/ultralytics/pull/1695
# img_h = shape[2] * self.stride[0]
# img_w = shape[3] * self.stride[0]
# img_size = torch.tensor([img_w, img_h, img_w, img_h], device=dbox.device).reshape(1, 4, 1)
# dbox /= img_size
# y = torch.cat((dbox, cls.sigmoid()), 1)
# return y if self.export else (y, x)
forward
method of class Segment(Detect):
def forward(self, x):
"""Return model outputs and mask coefficients if training, otherwise return outputs and mask coefficients."""
p = self.proto(x[0]) # mask protos
bs = p.shape[0] # batch size
mc = torch.cat([self.cv4[i](x[i]).view(bs, self.nm, -1) for i in range(self.nl)], 2) # mask coefficients
x = self.detect(self, x)
if self.training:
return x, mc, p
# return (torch.cat([x, mc], 1), p) if self.export else (torch.cat([x[0], mc], 1), (x[1], mc, p))
# !< https://github.com/FeiGeChuanShu/ncnn-android-yolov8
return (torch.cat([x, mc], 1).permute(0, 2, 1), p.view(bs, self.nm, -1)) if self.export else (torch.cat([x[0], mc], 1), (x[1], mc, p))
convert_seg.py
file under ~/Github/ultralytics
folderfrom ultralytics import YOLO
# Load model
model = YOLO("/home/tianzx/ai_model/seg/pf_phone_seg/pf_phone_yolov8n_seg.pt")
# Export model
success = model.export(task="segment", format="onnx", opset=12, imgsz=640, simplify=True)
$ cd ~/Github/
$ git clone https://github.com/Tencent/ncnn.git
$ cd ncnn
$ git submodule update --init
$ sudo apt install build-essential git cmake libprotobuf-dev protobuf-compiler libvulkan-dev vulkan-utils libopencv-dev
# build part
$ mkdir build && cd build
$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/ ..
$ make -j$(nproc)
$ sudo make install
$ cd /home/tianzx/ai_model/seg/pf_phone_seg/
$ onnx2ncnn pf_phone_yolov8n_seg.onnx pf_phone_yolov8n_seg.param pf_phone_yolov8n_seg.bin
$ ls
pf_phone_yolov8n_seg.bin pf_phone_yolov8n_seg.onnx pf_phone_yolov8n_seg.param pf_phone_yolov8n_seg.pt
CMakeLists.txt
and pf_phone_yolov8n_seg.cpp
CMakeLists.txt
$ cd /home/tianzx/ai_model/seg/pf_phone_seg/
$ vim CMakeLists.txt
$ vim pf_phone_yolov8n_seg.cpp
cmake_minimum_required(VERSION 3.5)
project(pf_phone_seg)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pie -fPIE -fPIC -Wall -O3")
find_package(OpenCV REQUIRED)
if (OpenCV_FOUND)
message(STATUS "OpenCV_LIBS: ${OpenCV_LIBS}")
message(STATUS "OpenCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}")
else ()
message(FATAL_ERROR "opencv Not Found!")
endif (OpenCV_FOUND)
find_package(OpenMP REQUIRED)
if (OPENMP_FOUND)
message("OPENMP FOUND")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
else ()
message(FATAL_ERROR "OpenMP Not Found!")
endif ()
include_directories(/usr/local/include)
include_directories(/usr/local/include/ncnn)
link_directories(/usr/local/lib)
# Source files
file(GLOB SRC "*.h" "*.cpp")
add_executable(pf_phone_seg ${SRC})
target_link_libraries(pf_phone_seg ncnn ${OpenCV_LIBS})
pf_phone_yolov8n_seg.cpp
#include "ncnn/net.h"
#if defined(USE_NCNN_SIMPLEOCV)
#include "simpleocv.h"
#else
#include
#include
#include
#endif
#include
#include
#include
#include
// !< add by tianzx 2023.10.20
#include
using namespace std;
using namespace cv;
static void slice(const ncnn::Mat& in, ncnn::Mat& out, int start, int end, int axis)
{
ncnn::Option opt;
opt.num_threads = 4;
opt.use_fp16_storage = false;
opt.use_packing_layout = false;
ncnn::Layer* op = ncnn::create_layer("Crop");
// set param
ncnn::ParamDict pd;
ncnn::Mat axes = ncnn::Mat(1);
axes.fill(axis);
ncnn::Mat ends = ncnn::Mat(1);
ends.fill(end);
ncnn::Mat starts = ncnn::Mat(1);
starts.fill(start);
pd.set(9, starts);// start
pd.set(10, ends);// end
pd.set(11, axes);//axes
op->load_param(pd);
op->create_pipeline(opt);
// forward
op->forward(in, out, opt);
op->destroy_pipeline(opt);
delete op;
}
static void interp(const ncnn::Mat& in, const float& scale, const int& out_w, const int& out_h, ncnn::Mat& out)
{
ncnn::Option opt;
opt.num_threads = 4;
opt.use_fp16_storage = false;
opt.use_packing_layout = false;
ncnn::Layer* op = ncnn::create_layer("Interp");
// set param
ncnn::ParamDict pd;
pd.set(0, 2);// resize_type
pd.set(1, scale);// height_scale
pd.set(2, scale);// width_scale
pd.set(3, out_h);// height
pd.set(4, out_w);// width
op->load_param(pd);
op->create_pipeline(opt);
// forward
op->forward(in, out, opt);
op->destroy_pipeline(opt);
delete op;
}
static void reshape(const ncnn::Mat& in, ncnn::Mat& out, int c, int h, int w, int d)
{
ncnn::Option opt;
opt.num_threads = 4;
opt.use_fp16_storage = false;
opt.use_packing_layout = false;
ncnn::Layer* op = ncnn::create_layer("Reshape");
// set param
ncnn::ParamDict pd;
pd.set(0, w);// start
pd.set(1, h);// end
if (d > 0)
pd.set(11, d);//axes
pd.set(2, c);//axes
op->load_param(pd);
op->create_pipeline(opt);
// forward
op->forward(in, out, opt);
op->destroy_pipeline(opt);
delete op;
}
static void sigmoid(ncnn::Mat& bottom)
{
ncnn::Option opt;
opt.num_threads = 4;
opt.use_fp16_storage = false;
opt.use_packing_layout = false;
ncnn::Layer* op = ncnn::create_layer("Sigmoid");
op->create_pipeline(opt);
// forward
op->forward_inplace(bottom, opt);
op->destroy_pipeline(opt);
delete op;
}
static void matmul(const std::vector& bottom_blobs, ncnn::Mat& top_blob)
{
ncnn::Option opt;
opt.num_threads = 2;
opt.use_fp16_storage = false;
opt.use_packing_layout = false;
ncnn::Layer* op = ncnn::create_layer("MatMul");
// set param
ncnn::ParamDict pd;
pd.set(0, 0);// axis
op->load_param(pd);
op->create_pipeline(opt);
std::vector top_blobs(1);
op->forward(bottom_blobs, top_blobs, opt);
top_blob = top_blobs[0];
op->destroy_pipeline(opt);
delete op;
}
struct Object
{
cv::Rect_ rect;
int label;
float prob;
cv::Mat mask;
std::vector mask_feat;
};
struct GridAndStride
{
int grid0;
int grid1;
int stride;
};
static inline float intersection_area(const Object& a, const Object& b)
{
cv::Rect_ inter = a.rect & b.rect;
return inter.area();
}
static void qsort_descent_inplace(std::vector
As the pf_phone_yolov8n_seg.pt
model is one instance segment model.
modify num_class = 8
to num_class = 1
in static void generate_proposals(std::vector
function.
modify class_names
and colors
variables in static void draw_objects(const cv::Mat& bgr, const std::vector
function.
$ cd /home/tianzx/ai_model/seg/pf_phone_seg/
$ mkdir build && cd build
$ cmake ..
$ make -j$(nproc)
$ ./pf_phone_seg ../pf_phone_yolov8n_seg.bin ../pf_phone_yolov8n_seg.param 640 /home/tianzx/Pictures/001_1.jpg
../pf_phone_yolov8n_seg.bin
../pf_phone_yolov8n_seg.param
640
/home/tianzx/Pictures/001_1.jpg
0 = 0.96407 at 102.32 91.11 859.72 x 406.88