Skip to content

Commit

Permalink
init Demo.
Browse files Browse the repository at this point in the history
  • Loading branch information
wangzhaode committed Mar 30, 2023
0 parents commit b2081b5
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# yolov8-mnn
23 changes: 23 additions & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.0)
project(mobilenet_demo)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

# include dir
include_directories(${CMAKE_CURRENT_LIST_DIR}/include/)

# libs dir
link_directories(${CMAKE_CURRENT_LIST_DIR}/libs)

# source files
FILE(GLOB SRCS ${CMAKE_CURRENT_LIST_DIR}/yolov8_demo.cpp)

# target
add_executable(yolov8_demo ${SRCS})

# link
if (MSVC)
target_link_libraries(yolov8_demo MNN)
else()
target_link_libraries(yolov8_demo MNN MNN_Express MNNOpenCV)
endif()
49 changes: 49 additions & 0 deletions cpp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Usage

## Compile MNN library
### Linx/Mac
```bash
git clone https://github.com/alibaba/MNN.git
cd MNN
# copy header file
cp -r include /path/to/MNNExample/mobilenet/cpp
cp -r tools/cv/include /path/to/MNNExample/yolov8/cpp
mkdir build
cmake -DMNN_BUILD_OPENCV=ON -DMNN_IMGCODECS=ON ..
make -j8
cp libMNN.so express/libMNN_Express.so tools/cv/libMNNOpenCV.so /path/to/MNNExample/yolov8/cpp/libs
```

### Windows
```bash
# Visual Studio xxxx Developer Command Prompt
powershell
git clone https://github.com/alibaba/MNN.git
cd MNN
# copy header file
cp -r include /path/to/MNNExample/mobilenet/cpp
cp -r tools/cv/include /path/to/MNNExample/yolov8/cpp
mkdir build
cmake -G "Ninja" -DMNN_BUILD_OPENCV=ON -DMNN_IMGCODECS=ON ..
ninja
cp MNN.dll MNN.lib /path/to/MNNExample/yolov8/cpp/build
```

## Build and Run

#### Linux/Mac
```bash
mkdir build && cd build
cmake ..
make -j4
./yolov8_demo yolov8n.mnn test.jpg
```
#### Windows
```bash
# Visual Studio xxxx Developer Command Prompt
powershell
mkdir build && cd build
cmake -G "Ninja" ..
ninja
./yolov8_demo yolov8n.mnn test.jpg
```
Empty file added cpp/include/.keep
Empty file.
Empty file added cpp/libs/.keep
Empty file.
100 changes: 100 additions & 0 deletions cpp/yolov8_demo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include <stdio.h>
#include <MNN/ImageProcess.hpp>
#include <MNN/expr/Module.hpp>
#include <MNN/expr/Executor.hpp>
#include <MNN/expr/ExprCreator.hpp>
#include <MNN/expr/Executor.hpp>

#include <cv/cv.hpp>

using namespace MNN;
using namespace MNN::Express;
using namespace MNN::CV;

int main(int argc, const char* argv[]) {
if (argc < 3) {
MNN_PRINT("Usage: ./yolov8_demo.out model.mnn input.jpg [forwardType] [precision] [thread]\n");
return 0;
}
int thread = 4;
int precision = 0;
int forwardType = MNN_FORWARD_CPU;
if (argc >= 4) {
forwardType = atoi(argv[3]);
}
if (argc >= 5) {
precision = atoi(argv[4]);
}
if (argc >= 6) {
thread = atoi(argv[5]);
}
MNN::ScheduleConfig sConfig;
sConfig.type = static_cast<MNNForwardType>(forwardType);
sConfig.numThread = thread;
BackendConfig bConfig;
bConfig.precision = static_cast<BackendConfig::PrecisionMode>(precision);
sConfig.backendConfig = &bConfig;
std::shared_ptr<Executor::RuntimeManager> rtmgr = std::shared_ptr<Executor::RuntimeManager>(Executor::RuntimeManager::createRuntimeManager(sConfig));
if(rtmgr == nullptr) {
MNN_ERROR("Empty RuntimeManger\n");
return 0;
}
rtmgr->setCache(".cachefile");

std::shared_ptr<Module> net(Module::load(std::vector<std::string>{}, std::vector<std::string>{}, argv[1], rtmgr));
auto original_image = imread(argv[2]);
auto dims = original_image->getInfo()->dim;
int ih = dims[0];
int iw = dims[1];
int len = ih > iw ? ih : iw;
float scale = len / 640.0;
std::vector<int> padvals { 0, len - ih, 0, len - iw, 0, 0 };
auto pads = _Const(static_cast<void*>(padvals.data()), {3, 2}, NCHW, halide_type_of<int>());
auto image = _Pad(original_image, pads, CONSTANT);
image = resize(image, Size(640, 640), 0, 0, INTER_LINEAR, -1, {0., 0., 0.}, {1./255., 1./255., 1./255.});
auto input = _Unsqueeze(image, {0});
input = _Convert(input, NC4HW4);
auto outputs = net->onForward({input});
auto output = _Convert(outputs[0], NCHW);
output = _Squeeze(output);
// output shape: [84, 8400]; 84 means: [cx, cy, w, h, prob * 80]
auto cx = _Gather(output, _Scalar<int>(0));
auto cy = _Gather(output, _Scalar<int>(1));
auto w = _Gather(output, _Scalar<int>(2));
auto h = _Gather(output, _Scalar<int>(3));
std::vector<int> startvals { 4, 0 };
auto start = _Const(static_cast<void*>(startvals.data()), {2}, NCHW, halide_type_of<int>());
std::vector<int> sizevals { -1, -1 };
auto size = _Const(static_cast<void*>(sizevals.data()), {2}, NCHW, halide_type_of<int>());
auto probs = _Slice(output, start, size);
// [cx, cy, w, h] -> [y0, x0, y1, x1]
auto x0 = cx - w * _Const(0.5);
auto y0 = cy - h * _Const(0.5);
auto x1 = cx + w * _Const(0.5);
auto y1 = cy + h * _Const(0.5);
auto boxes = _Stack({x0, y0, x1, y1}, 1);
auto scores = _ReduceMax(probs, {0});
auto ids = _ArgMax(probs, 0);
auto result_ids = _Nms(boxes, scores, 100, 0.45, 0.25);
auto result_ptr = result_ids->readMap<int>();
auto box_ptr = boxes->readMap<float>();
auto ids_ptr = ids->readMap<float>();
auto score_ptr = scores->readMap<float>();
for (int i = 0; i < 100; i++) {
auto idx = result_ptr[i];
if (idx < 0) break;
auto x0 = box_ptr[idx * 4 + 0] * scale;
auto y0 = box_ptr[idx * 4 + 1] * scale;
auto x1 = box_ptr[idx * 4 + 2] * scale;
auto y1 = box_ptr[idx * 4 + 3] * scale;
auto class_idx = ids_ptr[idx];
auto score = score_ptr[idx];
printf("### box: {%f, %f, %f, %f}, class_idx: %d, score: %f\n", x0, y0, x1, y1, idx, score);
rectangle(original_image, {x0, y0}, {x1, y1}, {0, 0, 255}, 2);
}
if (imwrite("res.jpg", original_image)) {
MNN_PRINT("result image write to `res.jpg`.\n");
}
rtmgr->updateCache();
return 0;
}
11 changes: 11 additions & 0 deletions python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Usage

## Install MNN
```
pip install MNN
```

## Run Demo
```
python yolov8_example.py --model yolov8n.mnn --img test.jpg
```
66 changes: 66 additions & 0 deletions python/yolov8_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#-- coding:utf8 --
import argparse

import MNN
import MNN.numpy as np
import MNN.cv as cv2

def inference(model, img, precision, backend, thread):
config = {}
config['precision'] = precision
config['backend'] = backend
config['numThread'] = thread
rt = MNN.nn.create_runtime_manager((config,))
# net = MNN.nn.load_module_from_file(model, ['images'], ['output0'], runtime_manager=rt)
net = MNN.nn.load_module_from_file(model, [], [], runtime_manager=rt)
original_image = cv2.imread(img)
ih, iw, _ = original_image.shape
length = max((ih, iw))
scale = length / 640
image = np.pad(original_image, [[0, length - ih], [0, length - iw], [0, 0]], 'constant')
image = cv2.resize(image, (640, 640), 0., 0., cv2.INTER_LINEAR, -1, [0., 0., 0.], [1./255., 1./255., 1./255.])
input_var = np.expand_dims(image, 0)
input_var = MNN.expr.convert(input_var, MNN.expr.NC4HW4)
output_var = net.forward(input_var)
output_var = MNN.expr.convert(output_var, MNN.expr.NCHW)
output_var = output_var.squeeze()
# output_var shape: [84, 8400]; 84 means: [cx, cy, w, h, prob * 80]
cx = output_var[0]
cy = output_var[1]
w = output_var[2]
h = output_var[3]
probs = output_var[4:]
# [cx, cy, w, h] -> [y0, x0, y1, x1]
x0 = cx - w * 0.5
y0 = cy - h * 0.5
x1 = cx + w * 0.5
y1 = cy + h * 0.5
boxes = np.stack([x0, y0, x1, y1], axis=1)
# get max prob and idx
scores = np.max(probs, 0)
class_ids = np.argmax(probs, 0)
result_ids = MNN.expr.nms(boxes, scores, 100, 0.45, 0.25)
print(result_ids.shape)
# nms result box, score, ids
result_boxes = boxes[result_ids]
result_scores = scores[result_ids]
result_class_ids = class_ids[result_ids]
for i in range(len(result_boxes)):
x0, y0, x1, y1 = result_boxes[i].read_as_tuple()
y0 = int(y0 * scale)
y1 = int(y1 * scale)
x0 = int(x0 * scale)
x1 = int(x1 * scale)
print(result_class_ids[i])
cv2.rectangle(original_image, (x0, y0), (x1, y1), (0, 0, 255), 2)
cv2.imwrite('res.jpg', original_image)

if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('--model', type=str, required=True, help='the mobilenet model path')
parser.add_argument('--img', type=str, required=True, help='the input image path')
parser.add_argument('--precision', type=str, default='normal', help='inference precision: normal, low, high, lowBF')
parser.add_argument('--backend', type=str, default='CPU', help='inference backend: CPU, OPENCL, OPENGL, NN, VULKAN, METAL, TRT, CUDA, HIAI')
parser.add_argument('--thread', type=int, default=4, help='inference using thread: int')
args = parser.parse_args()
inference(args.model, args.img, args.precision, args.backend, args.thread)

0 comments on commit b2081b5

Please sign in to comment.