EAIDK-610 实时图像分类

声明:

代码框架由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: [email protected]
 */

#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;
}
发布了44 篇原创文章 · 获赞 203 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/ReadAir/article/details/86666875