You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
546 lines
11 KiB
546 lines
11 KiB
2 years ago
|
//
|
||
2 years ago
|
// Created by ubuntu on 1/24/23.
|
||
2 years ago
|
//
|
||
2 years ago
|
#ifndef SEGMENT_SIMPLE_YOLOV8_SEG_HPP
|
||
|
#define SEGMENT_SIMPLE_YOLOV8_SEG_HPP
|
||
2 years ago
|
#include <fstream>
|
||
2 years ago
|
#include "common.hpp"
|
||
2 years ago
|
#include "NvInferPlugin.h"
|
||
|
|
||
|
using namespace seg;
|
||
|
|
||
|
class YOLOv8_seg
|
||
|
{
|
||
|
public:
|
||
|
explicit YOLOv8_seg(const std::string& engine_file_path);
|
||
|
~YOLOv8_seg();
|
||
|
|
||
|
void make_pipe(bool warmup = true);
|
||
|
void copy_from_Mat(const cv::Mat& image);
|
||
2 years ago
|
void copy_from_Mat(const cv::Mat& image, cv::Size& size);
|
||
|
void letterbox(
|
||
|
const cv::Mat& image,
|
||
|
cv::Mat& out,
|
||
|
cv::Size& size
|
||
|
);
|
||
2 years ago
|
void infer();
|
||
2 years ago
|
void postprocess(
|
||
|
std::vector<Object>& objs,
|
||
|
float score_thres = 0.25f,
|
||
|
float iou_thres = 0.65f,
|
||
|
int topk = 100,
|
||
|
int seg_channels = 32,
|
||
|
int seg_h = 160,
|
||
|
int seg_w = 160
|
||
|
);
|
||
|
static void draw_objects(
|
||
|
const cv::Mat& image,
|
||
|
cv::Mat& res,
|
||
|
const std::vector<Object>& objs,
|
||
|
const std::vector<std::string>& CLASS_NAMES,
|
||
|
const std::vector<std::vector<unsigned int>>& COLORS,
|
||
|
const std::vector<std::vector<unsigned int>>& MASK_COLORS
|
||
|
);
|
||
|
int num_bindings;
|
||
|
int num_inputs = 0;
|
||
|
int num_outputs = 0;
|
||
|
std::vector<Binding> input_bindings;
|
||
|
std::vector<Binding> output_bindings;
|
||
|
std::vector<void*> host_ptrs;
|
||
|
std::vector<void*> device_ptrs;
|
||
|
|
||
|
PreParam pparam;
|
||
2 years ago
|
private:
|
||
|
nvinfer1::ICudaEngine* engine = nullptr;
|
||
|
nvinfer1::IRuntime* runtime = nullptr;
|
||
|
nvinfer1::IExecutionContext* context = nullptr;
|
||
|
cudaStream_t stream = nullptr;
|
||
|
Logger gLogger{ nvinfer1::ILogger::Severity::kERROR };
|
||
|
|
||
|
};
|
||
|
|
||
|
YOLOv8_seg::YOLOv8_seg(const std::string& engine_file_path)
|
||
|
{
|
||
|
std::ifstream file(engine_file_path, std::ios::binary);
|
||
|
assert(file.good());
|
||
|
file.seekg(0, std::ios::end);
|
||
|
auto size = file.tellg();
|
||
|
file.seekg(0, std::ios::beg);
|
||
|
char* trtModelStream = new char[size];
|
||
|
assert(trtModelStream);
|
||
|
file.read(trtModelStream, size);
|
||
|
file.close();
|
||
|
initLibNvInferPlugins(&this->gLogger, "");
|
||
|
this->runtime = nvinfer1::createInferRuntime(this->gLogger);
|
||
|
assert(this->runtime != nullptr);
|
||
|
|
||
|
this->engine = this->runtime->deserializeCudaEngine(trtModelStream, size);
|
||
|
assert(this->engine != nullptr);
|
||
|
|
||
|
this->context = this->engine->createExecutionContext();
|
||
|
|
||
|
assert(this->context != nullptr);
|
||
|
cudaStreamCreate(&this->stream);
|
||
2 years ago
|
this->num_bindings = this->engine->getNbBindings();
|
||
|
|
||
|
for (int i = 0; i < this->num_bindings; ++i)
|
||
|
{
|
||
|
Binding binding;
|
||
|
nvinfer1::Dims dims;
|
||
|
nvinfer1::DataType dtype = this->engine->getBindingDataType(i);
|
||
|
std::string name = this->engine->getBindingName(i);
|
||
|
binding.name = name;
|
||
|
binding.dsize = type_to_size(dtype);
|
||
|
|
||
|
bool IsInput = engine->bindingIsInput(i);
|
||
|
if (IsInput)
|
||
|
{
|
||
|
this->num_inputs += 1;
|
||
|
dims = this->engine->getProfileDimensions(
|
||
|
i,
|
||
|
0,
|
||
|
nvinfer1::OptProfileSelector::kMAX);
|
||
|
binding.size = get_size_by_dims(dims);
|
||
|
binding.dims = dims;
|
||
|
this->input_bindings.push_back(binding);
|
||
|
// set max opt shape
|
||
|
this->context->setBindingDimensions(i, dims);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dims = this->context->getBindingDimensions(i);
|
||
|
binding.size = get_size_by_dims(dims);
|
||
|
binding.dims = dims;
|
||
|
this->output_bindings.push_back(binding);
|
||
|
this->num_outputs += 1;
|
||
|
}
|
||
|
}
|
||
2 years ago
|
|
||
|
}
|
||
|
|
||
|
YOLOv8_seg::~YOLOv8_seg()
|
||
|
{
|
||
|
this->context->destroy();
|
||
|
this->engine->destroy();
|
||
|
this->runtime->destroy();
|
||
|
cudaStreamDestroy(this->stream);
|
||
2 years ago
|
for (auto& ptr : this->device_ptrs)
|
||
2 years ago
|
{
|
||
|
CHECK(cudaFree(ptr));
|
||
|
}
|
||
|
|
||
2 years ago
|
for (auto& ptr : this->host_ptrs)
|
||
2 years ago
|
{
|
||
|
CHECK(cudaFreeHost(ptr));
|
||
|
}
|
||
|
}
|
||
2 years ago
|
|
||
2 years ago
|
void YOLOv8_seg::make_pipe(bool warmup)
|
||
|
{
|
||
|
|
||
2 years ago
|
for (auto& bindings : this->input_bindings)
|
||
|
{
|
||
|
void* d_ptr;
|
||
|
CHECK(cudaMallocAsync(
|
||
|
&d_ptr,
|
||
|
bindings.size * bindings.dsize,
|
||
|
this->stream)
|
||
|
);
|
||
|
this->device_ptrs.push_back(d_ptr);
|
||
|
}
|
||
2 years ago
|
|
||
2 years ago
|
for (auto& bindings : this->output_bindings)
|
||
2 years ago
|
{
|
||
2 years ago
|
void* d_ptr, * h_ptr;
|
||
|
size_t size = bindings.size * bindings.dsize;
|
||
|
CHECK(cudaMallocAsync(
|
||
|
&d_ptr,
|
||
|
size,
|
||
|
this->stream)
|
||
|
);
|
||
|
CHECK(cudaHostAlloc(
|
||
|
&h_ptr,
|
||
|
size,
|
||
|
0)
|
||
|
);
|
||
|
this->device_ptrs.push_back(d_ptr);
|
||
|
this->host_ptrs.push_back(h_ptr);
|
||
2 years ago
|
}
|
||
2 years ago
|
|
||
2 years ago
|
if (warmup)
|
||
|
{
|
||
|
for (int i = 0; i < 10; i++)
|
||
|
{
|
||
2 years ago
|
for (auto& bindings : this->input_bindings)
|
||
|
{
|
||
|
size_t size = bindings.size * bindings.dsize;
|
||
|
void* h_ptr = malloc(size);
|
||
|
memset(h_ptr, 0, size);
|
||
|
CHECK(cudaMemcpyAsync(
|
||
|
this->device_ptrs[0],
|
||
|
h_ptr,
|
||
|
size,
|
||
|
cudaMemcpyHostToDevice,
|
||
|
this->stream)
|
||
|
);
|
||
|
free(h_ptr);
|
||
|
}
|
||
2 years ago
|
this->infer();
|
||
|
}
|
||
|
printf("model warmup 10 times\n");
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
2 years ago
|
void YOLOv8_seg::letterbox(
|
||
|
const cv::Mat& image,
|
||
|
cv::Mat& out,
|
||
|
cv::Size& size
|
||
|
)
|
||
2 years ago
|
{
|
||
2 years ago
|
const float inp_h = size.height;
|
||
|
const float inp_w = size.width;
|
||
|
float height = image.rows;
|
||
|
float width = image.cols;
|
||
2 years ago
|
|
||
2 years ago
|
float r = std::min(inp_h / height, inp_w / width);
|
||
|
int padw = std::round(width * r);
|
||
|
int padh = std::round(height * r);
|
||
2 years ago
|
|
||
|
cv::Mat tmp;
|
||
|
if ((int)width != padw || (int)height != padh)
|
||
|
{
|
||
2 years ago
|
cv::resize(
|
||
|
image,
|
||
|
tmp,
|
||
|
cv::Size(padw, padh)
|
||
|
);
|
||
2 years ago
|
}
|
||
|
else
|
||
|
{
|
||
|
tmp = image.clone();
|
||
|
}
|
||
|
|
||
2 years ago
|
float dw = inp_w - padw;
|
||
|
float dh = inp_h - padh;
|
||
2 years ago
|
|
||
2 years ago
|
dw /= 2.0f;
|
||
|
dh /= 2.0f;
|
||
|
int top = int(std::round(dh - 0.1f));
|
||
|
int bottom = int(std::round(dh + 0.1f));
|
||
|
int left = int(std::round(dw - 0.1f));
|
||
|
int right = int(std::round(dw + 0.1f));
|
||
|
|
||
|
cv::copyMakeBorder(
|
||
2 years ago
|
tmp,
|
||
2 years ago
|
tmp,
|
||
|
top,
|
||
|
bottom,
|
||
|
left,
|
||
|
right,
|
||
|
cv::BORDER_CONSTANT,
|
||
|
{ 114, 114, 114 }
|
||
|
);
|
||
|
|
||
|
cv::dnn::blobFromImage(tmp,
|
||
|
out,
|
||
2 years ago
|
1 / 255.f,
|
||
|
cv::Size(),
|
||
|
cv::Scalar(0, 0, 0),
|
||
|
true,
|
||
|
false,
|
||
2 years ago
|
CV_32F
|
||
|
);
|
||
|
this->pparam.ratio = 1 / r;
|
||
|
this->pparam.dw = dw;
|
||
|
this->pparam.dh = dh;
|
||
|
this->pparam.height = height;
|
||
|
this->pparam.width = width;;
|
||
|
}
|
||
|
|
||
|
void YOLOv8_seg::copy_from_Mat(const cv::Mat& image)
|
||
|
{
|
||
|
cv::Mat nchw;
|
||
|
auto& in_binding = this->input_bindings[0];
|
||
|
auto width = in_binding.dims.d[3];
|
||
|
auto height = in_binding.dims.d[2];
|
||
|
cv::Size size{ width, height };
|
||
|
this->letterbox(
|
||
|
image,
|
||
|
nchw,
|
||
|
size
|
||
|
);
|
||
|
|
||
|
this->context->setBindingDimensions(
|
||
|
0,
|
||
|
nvinfer1::Dims
|
||
|
{
|
||
|
4,
|
||
|
{ 1, 3, height, width }
|
||
|
}
|
||
|
);
|
||
|
|
||
|
CHECK(cudaMemcpyAsync(
|
||
|
this->device_ptrs[0],
|
||
|
nchw.ptr<float>(),
|
||
|
nchw.total() * nchw.elemSize(),
|
||
2 years ago
|
cudaMemcpyHostToDevice,
|
||
2 years ago
|
this->stream)
|
||
|
);
|
||
|
}
|
||
2 years ago
|
|
||
2 years ago
|
void YOLOv8_seg::copy_from_Mat(const cv::Mat& image, cv::Size& size)
|
||
|
{
|
||
|
cv::Mat nchw;
|
||
|
this->letterbox(
|
||
|
image,
|
||
|
nchw,
|
||
|
size
|
||
|
);
|
||
|
this->context->setBindingDimensions(
|
||
|
0,
|
||
|
nvinfer1::Dims
|
||
|
{ 4,
|
||
|
{ 1, 3, size.height, size.width }
|
||
|
}
|
||
|
);
|
||
|
CHECK(cudaMemcpyAsync(
|
||
|
this->device_ptrs[0],
|
||
|
nchw.ptr<float>(),
|
||
|
nchw.total() * nchw.elemSize(),
|
||
|
cudaMemcpyHostToDevice,
|
||
|
this->stream)
|
||
|
);
|
||
2 years ago
|
}
|
||
|
|
||
|
void YOLOv8_seg::infer()
|
||
|
{
|
||
2 years ago
|
|
||
|
this->context->enqueueV2(
|
||
|
this->device_ptrs.data(),
|
||
|
this->stream,
|
||
|
nullptr
|
||
|
);
|
||
|
for (int i = 0; i < this->num_outputs; i++)
|
||
2 years ago
|
{
|
||
2 years ago
|
size_t osize = this->output_bindings[i].size * this->output_bindings[i].dsize;
|
||
|
CHECK(cudaMemcpyAsync(this->host_ptrs[i],
|
||
|
this->device_ptrs[i + this->num_inputs],
|
||
2 years ago
|
osize,
|
||
|
cudaMemcpyDeviceToHost,
|
||
2 years ago
|
this->stream)
|
||
|
);
|
||
|
|
||
2 years ago
|
}
|
||
|
cudaStreamSynchronize(this->stream);
|
||
|
|
||
|
}
|
||
|
|
||
2 years ago
|
void YOLOv8_seg::postprocess(std::vector<Object>& objs,
|
||
|
float score_thres,
|
||
|
float iou_thres,
|
||
|
int topk,
|
||
|
int seg_channels,
|
||
|
int seg_h,
|
||
|
int seg_w
|
||
|
)
|
||
2 years ago
|
{
|
||
|
objs.clear();
|
||
2 years ago
|
auto input_h = this->input_bindings[0].dims.d[2];
|
||
|
auto input_w = this->input_bindings[0].dims.d[3];
|
||
|
auto num_anchors = this->output_bindings[0].dims.d[1];
|
||
|
auto num_channels = this->output_bindings[0].dims.d[2];
|
||
|
|
||
|
auto& dw = this->pparam.dw;
|
||
|
auto& dh = this->pparam.dh;
|
||
|
auto& width = this->pparam.width;
|
||
|
auto& height = this->pparam.height;
|
||
|
auto& ratio = this->pparam.ratio;
|
||
|
|
||
|
auto* output = static_cast<float*>(this->host_ptrs[0]);
|
||
|
cv::Mat protos = cv::Mat(seg_channels, seg_h * seg_w, CV_32F,
|
||
|
static_cast<float*>(this->host_ptrs[1]));
|
||
2 years ago
|
|
||
|
std::vector<int> labels;
|
||
|
std::vector<float> scores;
|
||
|
std::vector<cv::Rect> bboxes;
|
||
|
std::vector<cv::Mat> mask_confs;
|
||
2 years ago
|
std::vector<int> indices;
|
||
2 years ago
|
|
||
2 years ago
|
for (int i = 0; i < num_anchors; i++)
|
||
2 years ago
|
{
|
||
2 years ago
|
float* ptr = output + i * num_channels;
|
||
2 years ago
|
float score = *(ptr + 4);
|
||
2 years ago
|
if (score > score_thres)
|
||
2 years ago
|
{
|
||
2 years ago
|
float x0 = *ptr++ - dw;
|
||
|
float y0 = *ptr++ - dh;
|
||
|
float x1 = *ptr++ - dw;
|
||
|
float y1 = *ptr++ - dh;
|
||
2 years ago
|
|
||
2 years ago
|
x0 = clamp(x0 * ratio, 0.f, width);
|
||
|
y0 = clamp(y0 * ratio, 0.f, height);
|
||
|
x1 = clamp(x1 * ratio, 0.f, width);
|
||
|
y1 = clamp(y1 * ratio, 0.f, height);
|
||
2 years ago
|
|
||
|
int label = *(++ptr);
|
||
2 years ago
|
cv::Mat mask_conf = cv::Mat(1, seg_channels, CV_32F, ++ptr);
|
||
2 years ago
|
mask_confs.push_back(mask_conf);
|
||
|
labels.push_back(label);
|
||
|
scores.push_back(score);
|
||
|
bboxes.push_back(cv::Rect_<float>(x0, y0, x1 - x0, y1 - y0));
|
||
2 years ago
|
|
||
2 years ago
|
}
|
||
|
}
|
||
2 years ago
|
|
||
2 years ago
|
#if defined(BATCHED_NMS)
|
||
2 years ago
|
cv::dnn::NMSBoxesBatched(
|
||
|
bboxes,
|
||
|
scores,
|
||
|
labels,
|
||
|
score_thres,
|
||
|
iou_thres,
|
||
|
indices
|
||
|
);
|
||
2 years ago
|
#else
|
||
2 years ago
|
cv::dnn::NMSBoxes(
|
||
|
bboxes,
|
||
|
scores,
|
||
|
score_thres,
|
||
|
iou_thres,
|
||
|
indices
|
||
|
);
|
||
2 years ago
|
#endif
|
||
|
|
||
|
cv::Mat masks;
|
||
2 years ago
|
int cnt = 0;
|
||
2 years ago
|
for (auto& i : indices)
|
||
|
{
|
||
2 years ago
|
if (cnt >= topk)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
2 years ago
|
cv::Rect tmp = bboxes[i];
|
||
|
Object obj;
|
||
|
obj.label = labels[i];
|
||
|
obj.rect = tmp;
|
||
|
obj.prob = scores[i];
|
||
|
masks.push_back(mask_confs[i]);
|
||
|
objs.push_back(obj);
|
||
2 years ago
|
cnt += 1;
|
||
2 years ago
|
}
|
||
|
|
||
|
cv::Mat matmulRes = (masks * protos).t();
|
||
2 years ago
|
cv::Mat maskMat = matmulRes.reshape(indices.size(), { seg_w, seg_h });
|
||
2 years ago
|
|
||
|
std::vector<cv::Mat> maskChannels;
|
||
|
cv::split(maskMat, maskChannels);
|
||
2 years ago
|
int scale_dw = dw / input_w * seg_w;
|
||
|
int scale_dh = dh / input_h * seg_h;
|
||
2 years ago
|
|
||
|
cv::Rect roi(
|
||
|
scale_dw,
|
||
|
scale_dh,
|
||
2 years ago
|
seg_w - 2 * scale_dw,
|
||
|
seg_h - 2 * scale_dh);
|
||
2 years ago
|
|
||
|
for (int i = 0; i < indices.size(); i++)
|
||
|
{
|
||
|
cv::Mat dest, mask;
|
||
|
cv::exp(-maskChannels[i], dest);
|
||
|
dest = 1.0 / (1.0 + dest);
|
||
|
dest = dest(roi);
|
||
2 years ago
|
cv::resize(
|
||
|
dest,
|
||
|
mask,
|
||
|
cv::Size((int)width, (int)height),
|
||
|
cv::INTER_LINEAR
|
||
|
);
|
||
|
objs[i].boxMask = mask(objs[i].rect) > 0.5f;
|
||
2 years ago
|
}
|
||
|
|
||
|
}
|
||
|
|
||
2 years ago
|
void YOLOv8_seg::draw_objects(const cv::Mat& image,
|
||
|
cv::Mat& res,
|
||
|
const std::vector<Object>& objs,
|
||
|
const std::vector<std::string>& CLASS_NAMES,
|
||
|
const std::vector<std::vector<unsigned int>>& COLORS,
|
||
|
const std::vector<std::vector<unsigned int>>& MASK_COLORS
|
||
|
)
|
||
2 years ago
|
{
|
||
|
res = image.clone();
|
||
|
cv::Mat mask = image.clone();
|
||
|
for (auto& obj : objs)
|
||
|
{
|
||
|
int idx = obj.label;
|
||
2 years ago
|
cv::Scalar color = cv::Scalar(
|
||
|
COLORS[idx][0],
|
||
|
COLORS[idx][1],
|
||
|
COLORS[idx][2]
|
||
|
);
|
||
2 years ago
|
cv::Scalar mask_color = cv::Scalar(
|
||
2 years ago
|
MASK_COLORS[idx % 20][0],
|
||
|
MASK_COLORS[idx % 20][1],
|
||
|
MASK_COLORS[idx % 20][2]
|
||
|
);
|
||
|
cv::rectangle(
|
||
|
res,
|
||
|
obj.rect,
|
||
|
color,
|
||
|
2
|
||
|
);
|
||
2 years ago
|
|
||
|
char text[256];
|
||
2 years ago
|
sprintf(
|
||
|
text,
|
||
|
"%s %.1f%%",
|
||
|
CLASS_NAMES[idx].c_str(),
|
||
|
obj.prob * 100
|
||
|
);
|
||
2 years ago
|
mask(obj.rect).setTo(mask_color, obj.boxMask);
|
||
|
|
||
|
int baseLine = 0;
|
||
2 years ago
|
cv::Size label_size = cv::getTextSize(
|
||
|
text,
|
||
|
cv::FONT_HERSHEY_SIMPLEX,
|
||
|
0.4,
|
||
|
1,
|
||
|
&baseLine
|
||
|
);
|
||
2 years ago
|
|
||
|
int x = (int)obj.rect.x;
|
||
|
int y = (int)obj.rect.y + 1;
|
||
|
|
||
|
if (y > res.rows)
|
||
|
y = res.rows;
|
||
|
|
||
2 years ago
|
cv::rectangle(
|
||
|
res,
|
||
|
cv::Rect(x, y, label_size.width, label_size.height + baseLine),
|
||
|
{ 0, 0, 255 },
|
||
|
-1
|
||
|
);
|
||
|
|
||
|
cv::putText(
|
||
|
res,
|
||
|
text,
|
||
|
cv::Point(x, y + label_size.height),
|
||
|
cv::FONT_HERSHEY_SIMPLEX,
|
||
|
0.4,
|
||
|
{ 255, 255, 255 },
|
||
|
1
|
||
|
);
|
||
2 years ago
|
}
|
||
2 years ago
|
cv::addWeighted(
|
||
|
res,
|
||
|
0.5,
|
||
|
mask,
|
||
|
0.8,
|
||
|
1,
|
||
|
res
|
||
|
);
|
||
2 years ago
|
}
|
||
2 years ago
|
#endif //SEGMENT_SIMPLE_YOLOV8_SEG_HPP
|