声明:
代码框架由EAIDK-610板卡工程师提供。
[编辑] 经过工程师提醒,删改了一些代码,使得运行效率更高(2019.1.28 21:28)
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* License); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
/*
* Copyright (c) 2018, Open AI Lab
* Author: chunyinglv@openailab.com
*/
#include <unistd.h>
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
//#include "opencv2/imgproc/imgproc.hpp"
//#include "opencv2/highgui/highgui.hpp"
#include "tengine_c_api.h"
#include <sys/time.h>
#include "mipi_cam.hpp"
//ReadAir Added
//#include "fastcv.hpp"
#define DEF_MODEL "models/MobileNetSSD_deploy.tmfile"
struct Box
{
float x0;
float y0;
float x1;
float y1;
int class_idx;
float score;
};
//ReadAir修改:读取图片地址改为直接输入矩阵
void get_input_data_ssd(cv::Mat img, float* input_data, int img_h, int img_w)
{
//cv::Mat img_out;
//img_out.create(cv::Size(RGA_ALIGN(img_w, 16), RGA_ALIGN(img_h, 16)), CV_8UC3);
img.convertTo(img, CV_32FC3);
cv::resize(img, img, cv::Size(img_h, img_w));
float* img_data = ( float* )img.data;
int hw = img_h * img_w;
float mean[3] = {127.5, 127.5, 127.5};
for(int h = 0; h < img_h; h++)
{
for(int w = 0; w < img_w; w++)
{
for(int c = 0; c < 3; c++)
{
input_data[c * hw + h * img_w + w] = 0.007843 * (*img_data - mean[c]);
img_data++;
}
}
}
}
//ReadAir:使用实时图像,修改图片输入输出格式
void post_process_ssd(cv::Mat img, float threshold, float* outdata, int num)
{
const char* class_names[] = {"background", "aeroplane", "bicycle", "bird", "boat", "bottle",
"bus", "car", "cat", "chair", "cow", "diningtable",
"dog", "horse", "motorbike", "person", "pottedplant", "sheep",
"sofa", "train", "tvmonitor"};
int raw_h = img.size().height;
int raw_w = img.size().width;
std::vector<Box> boxes;
int line_width = raw_w * 0.005;
printf("detect result num: %d \n", num);
for(int i = 0; i < num; i++)
{
if(outdata[1] >= threshold)
{
Box box;
box.class_idx = outdata[0];
box.score = outdata[1];
box.x0 = outdata[2] * raw_w;
box.y0 = outdata[3] * raw_h;
box.x1 = outdata[4] * raw_w;
box.y1 = outdata[5] * raw_h;
boxes.push_back(box);
printf("%s\t:%.3f%%\n", class_names[box.class_idx], box.score * 100);
printf("BOX:( %g , %g ),( %g , %g )\n", box.x0, box.y0, box.x1, box.y1);
}
outdata += 6;
}
for(int i = 0; i < ( int )boxes.size(); i++)
{
Box box = boxes[i];
cv::rectangle(img, cv::Rect(box.x0, box.y0, (box.x1 - box.x0), (box.y1 - box.y0)), cv::Scalar(255, 255, 0),
line_width);
std::ostringstream score_str;
score_str << box.score;
std::string label = std::string(class_names[box.class_idx]) + ": " + score_str.str();
int baseLine = 0;
cv::Size label_size = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
cv::rectangle(img,
cv::Rect(cv::Point(box.x0, box.y0 - label_size.height),
cv::Size(label_size.width, label_size.height + baseLine)),
cv::Scalar(255, 255, 0), CV_FILLED);
cv::putText(img, label, cv::Point(box.x0, box.y0), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
}
}
int main(int argc, char* argv[])
{
int ret = -1;
const char* device = nullptr;
// init tengine
if(init_tengine() < 0)
{
std::cout << " init tengine failed\n";
return 1;
}
if(request_tengine_version("0.9") != 1)
{
std::cout << " request tengine version failed\n";
return 1;
}
// create graph
graph_t graph = create_graph(nullptr, "tengine", "models/MobileNetSSD_deploy.tmfile");
if(graph == nullptr)
{
std::cout << "Create graph failed\n";
std::cout << " ,errno: " << get_tengine_errno() << "\n";
return 1;
}
if(device != nullptr)
{
set_graph_device(graph, device);
}
// input
int img_h = 240;
int img_w = 240;
int img_size = img_h * img_w * 3;
float* input_data = ( float* )malloc(sizeof(float) * img_size);
int node_idx = 0;
int tensor_idx = 0;
tensor_t input_tensor = get_graph_input_tensor(graph, node_idx, tensor_idx);
if(input_tensor == nullptr)
{
std::printf("Cannot find input tensor,node_idx: %d,tensor_idx: %d\n", node_idx, tensor_idx);
return -1;
}
int dims[] = {1, 3, img_h, img_w};
set_tensor_shape(input_tensor, dims, 4);
ret = prerun_graph(graph);
if(ret != 0)
{
std::cout << "Prerun graph failed, errno: " << get_tengine_errno() << "\n";
return 1;
}
int repeat_count = 1;
const char* repeat = std::getenv("REPEAT_COUNT");
if(repeat)
repeat_count = std::strtoul(repeat, NULL, 10);
//ReadAir补充:MIPI相机的初始化与视频流开启
char v4l2_dev[64], isp_dev[64];
char index = -1;
const string wintitle = "mipi-camera";
/* MIPI Camera -- default values */
int mipi = 1; /* main camera */
enum CAM_TYPE type = CAM_OV9750; /* HD camera sensor: OV9750 */
__u32 width = 320,height = 240; /* resolution: 640x480 */
RgaRotate rotate = RGA_ROTATE_NONE; /* No rotation */
__u32 cropx = 0, cropy = 0, cropw = 0, croph = 0;
int vflip = 0, hflip = 0; /* no flip */
/* Window -- 创建窗口 */
fcv::namedWindow(wintitle);
fcv::moveWindow(wintitle, 720, 480);
/* V4L2 device */
sprintf(v4l2_dev, "/dev/video%d", 4 * (mipi - 1) + 2);
sprintf(isp_dev, "/dev/video%d", 4 * (mipi - 1) + 1);
/* MIPI Camera -- initialization */
fcv::Mat image,image_out;
v4l2Camera v4l2(width, height, rotate, vflip, hflip, cropx, cropy, cropw, croph, V4L2_PIX_FMT_NV12);
image.create(cv::Size(RGA_ALIGN(width, 16), RGA_ALIGN(height, 16)), CV_8UC3);
image_out.create(cv::Size(RGA_ALIGN(width, 16), RGA_ALIGN(height, 16)), CV_8UC3);
ret = v4l2.init(v4l2_dev, isp_dev, type);
if (ret < 0)
{
printf("v4l2Camera initialization failed.\n");
return ret;
}
/* MIPI Camera -- open stream */
ret = v4l2.streamOn();
if (ret < 0)
return ret;
tensor_t out_tensor = get_graph_output_tensor(graph, 0, 0);
while (1)
{
/* MIPI Camera -- 读取视屏一帧e */
ret = v4l2.readFrame(V4L2_PIX_FMT_RGB24, image);
if (ret != 0)
{
std::cout << "get image failed \n";
return ret;
}
// warm up
get_input_data_ssd(image, input_data, img_h, img_w);
set_tensor_buffer(input_tensor, input_data, img_size * 4);
ret = run_graph(graph, 1);
if (ret != 0)
{
std::cout << "Run graph failed, errno: " << get_tengine_errno() << "\n";
return 1;
}
int out_dim[4];
ret = get_tensor_shape(out_tensor, out_dim, 4);
if (ret <= 0)
{
std::cout << "get tensor shape failed, errno: " << get_tengine_errno() << "\n";
return 1;
}
float* outdata = (float*)get_tensor_buffer(out_tensor);
int num = out_dim[1];
float show_threshold = 0.5;
post_process_ssd(image, show_threshold, outdata, num);
/* Window -- 画出一帧 */
fcv::imshow(wintitle, image, NULL);
fcv::waitKey(1);
}
release_graph_tensor(out_tensor);
release_graph_tensor(input_tensor);
ret = postrun_graph(graph);
if(ret != 0)
{
std::cout << "Postrun graph failed, errno: " << get_tengine_errno() << "\n";
return 1;
}
free(input_data);
destroy_graph(graph);
release_tengine();
return 0;
}