Android 经典蓝牙(Classic Bluetooth)和低功耗蓝牙(BLE)

news/2024/11/24 14:14:58/

从蓝牙4.0开始包含两个蓝牙芯片模块:传统/经典蓝牙模块(Classic Bluetooth,简称BT)和低功耗蓝牙(Bluetooth Low Energy,简称BLE)

经典蓝牙是在之前的蓝牙1.0,1.2,2.0 EDR,2.1 EDR,3.0 EDR等基础上发展和完善起来的, 而低功耗蓝牙是Nokia的Wibree标准上发展起来的,是完全不同两个标准。

蓝牙文件:url80.ctfile.com/f/25127180-741945753-c5f62a?p=551685 (访问密码: 551685)

1.经典蓝牙模块(BT)

泛指蓝牙4.0以下的模块,一般用于数据量比较大的传输,如:语音、音乐、较高数据量传输等。

经典蓝牙模块可再细分为:传统蓝牙模块和高速蓝牙模块。

传统蓝牙模块在2004年推出,主要代表是支持蓝牙2.1协议的模块,在智能手机爆发的时期得到广泛支持。

高速蓝牙模块在2009年推出,速率提高到约24Mbps,是传统蓝牙模块的八倍。

传统蓝牙有3个功率级别,Class1,Class2,Class3,分别支持100m,10m,1m的传输距离

2.低功耗蓝牙模块(BLE)

泛指蓝牙4.0或更高的模块,蓝牙低功耗技术是低成本、短距离、可互操作的鲁棒性无线技术,工作在免许可的2.4GHz ISM射频频段。

因为BLE技术采用非常快速的连接方式,因此平时可以处于“非连接”状态(节省能源),

此时链路两端相互间只是知晓对方,只有在必要时才开启链路,然后在尽可能短的时间内关闭链路(每次最多传输20字节)。

低功耗蓝牙无功率级别,一般发送功率在7dBm,一般在空旷距离,达到20m应该是没有问题。


OpenVINO计算机视觉模型加速
OpenVINO介绍
计算机视觉部署框架,支持多种边缘硬件平台
Intel开发并开源使用的计算机视觉库
支持多个场景视觉任务场景的快速演示

四个主要模块:

1、开发环境搭建
安装cmake、Miniconda3、Notepad++、PyCharm、VisualStudio 2019

注意:安装Miniconda3一定要设置其自动添加环境变量,需要添加5个环境变量,手动添加很可能会漏掉,排错困难

下载OpenVINO并安装:[Download Intel® Distribution of OpenVINO™ Toolkit](https://www.intel.com/content/www/us/en/developer/tools/openvino-toolkit/download-previous-versions.html?operatingsystem=window&distributions=webdownload&version=2021 4.2 LTS&options=offline)

安装完毕后运行测试程序

出现下面运行结果代表安装配置成功

添加OpenVINO环境变量

配置VisualStudio包含目录、库目录及附加依赖项

运行以下脚本自动获取附加依赖项

添加附加依赖项

至此,开发环境搭建完毕!

2、SDK介绍与开发流程

inference_engine.dll 推理引擎

依赖支持:inference_engine_transformations.dll, tbb.dll, tbbmalloc.dll, ngraph.dll

一定要把这些dll文件都添加到 C:/Windows/System32 中才可以正常运行OpenVINO程序

InferenceEngine相关API函数支持
InferenceEngine::Core
InferenceEngine::Blob, InferenceEngine::TBlob, InferenceEngine::NV12Blob
InferenceEngine::BlobMap
InferenceEngine::InputsDataMap, InferenceEngine::InputInfo
InferenceEngine::OutputsDataMap
InferenceEngine核心库的包装类
InferenceEngine::CNNNetwork
InferenceEngine::ExecutableNetwork
InferenceEngine::InferRequest
代码实现
#include <inference_engine.hpp>
#include

using namespace InferenceEngine;

int main(int argc, char** argv) {

InferenceEngine::Core ie;  //使用推理引擎获取可用的设备及cpu全称
std::vector<std::string> devices = ie.GetAvailableDevices();
for (std::string name : devices) {std::cout << "device name: " << name << std::endl;
}
std::string cpuName = ie.GetMetric("CPU", METRIC_KEY(FULL_DEVICE_NAME)).as<std::string>();
std::cout << "cpu full name: " << cpuName << std::endl;return 0;

}
效果:

3、ResNet18实现图像分类
预训练模型介绍 - ResNet18
预处理图像
mean = [0.485, 0.456, 0.406], std = [0.229, 0.224, 0.225],图像归一化后再减去均值,除以方差
输入:NCHW = 1 * 3 * 224 * 224 (num,channels,height,width)
输出格式:1 * 1000
代码实现整体步骤
初始化Core ie
ie.ReadNetwork
获取输入与输出格式并设置精度
获取可执行网络并链接硬件
auto executable_network = ie.LoadNetwork(network, “CPU”);
创建推理请求
auto infer_request = executable_network.CreateInferRequest();
设置输入数据 - 图像数据预处理
推理并解析输出
代码实现
#include <inference_engine.hpp>
#include <opencv2/opencv.hpp>
#include //fstream文件读写操作,iostream为控制台操作

using namespace InferenceEngine;
std::string labels_txt_file = “D:/projects/models/resnet18_ir/imagenet_classes.txt”;
std::vectorstd::string readClassNames();

int main(int argc, char** argv) {

InferenceEngine::Core ie;
std::vector<std::string> devices = ie.GetAvailableDevices();
for (std::string name : devices) {std::cout << "device name: " << name << std::endl;
}
std::string cpuName = ie.GetMetric("CPU", METRIC_KEY(FULL_DEVICE_NAME)).as<std::string>();
std::cout << "cpu name: " << cpuName << std::endl;std::string xml = "D:/projects/models/resnet18_ir/resnet18.xml";
std::string bin = "D:/projects/models/resnet18_ir/resnet18.bin";
std::vector<std::string> labels = readClassNames();  //读取标签
cv::Mat src = cv::imread("D:/images/messi.jpg");  //读取图像
InferenceEngine::CNNNetwork network = ie.ReadNetwork(xml, bin);  //读取resnet18网络InferenceEngine::InputsDataMap inputs = network.getInputsInfo();  //DataMap是一个Mat数组
InferenceEngine::OutputsDataMap outputs = network.getOutputsInfo();  //DataMap是一个Mat数组
std::string input_name = "";
for (auto item : inputs) {  //auto可以自动推断变量类型input_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto input_data = item.second;input_data->setPrecision(Precision::FP32);input_data->setLayout(Layout::NCHW);input_data->getPreProcess().setColorFormat(ColorFormat::RGB);std::cout << "input name: " << input_name << std::endl;
}
std::string output_name = "";
for (auto item : outputs) {  //auto可以自动推断变量类型output_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto output_data = item.second;output_data->setPrecision(Precision::FP32);//注意:output_data不要设置结构std::cout << "output name: " << output_name << std::endl;
}auto executable_network = ie.LoadNetwork(network, "CPU");  //设置运行的设备
auto infer_request = executable_network.CreateInferRequest();  //设置推理请求//图像预处理
auto input = infer_request.GetBlob(input_name);  //获取网络输入图像信息
size_t num_channels = input->getTensorDesc().getDims()[1];  //size_t 类型表示C中任何对象所能达到的最大长度,它是无符号整数
size_t h = input->getTensorDesc().getDims()[2];
size_t w = input->getTensorDesc().getDims()[3];
size_t image_size = h * w;
cv::Mat blob_image;
cv::resize(src, blob_image, cv::Size(w, h));  //将输入图片大小转换为与网络输入大小一致
blob_image.convertTo(blob_image, CV_32F);  //将输入图像转换为浮点数
blob_image = blob_image / 255.0;
cv::subtract(blob_image, cv::Scalar(0.485, 0.456, 0.406), blob_image);
cv::divide(blob_image, cv::Scalar(0.229, 0.224, 0.225), blob_image);
// HWC =》NCHW  将输入图像从HWC格式转换为NCHW格式
float* data = static_cast<float*>(input->buffer());  //将图像放到buffer中,放入input中
for (size_t row = 0; row < h; row++) {for (size_t col = 0; col < w; col++) {for (size_t ch = 0; ch < num_channels; ch++) {//将每个通道变成一张图,按照通道顺序data[image_size * ch + row * w + col] = blob_image.at<cv::Vec3f>(row, col)[ch];}}
}infer_request.Infer();
auto output = infer_request.GetBlob(output_name);
//转换输出数据
const float* probs = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(output->buffer());
const SizeVector outputDims = output->getTensorDesc().getDims();  //获取输出维度信息 1*1000
std::cout << outputDims[0] << "x" << outputDims[1] << std::endl;
float max = probs[0];
int max_index = 0;
for (int i = 1; i < outputDims[1]; i++) {if (max < probs[i]) {  //找到结果probs中的最大值,获取其下标max = probs[i];max_index = i;}
}
std::cout << "class index: " << max_index << std::endl;
std::cout << "class name: " << labels[max_index] << std::endl;
cv::putText(src, labels[max_index], cv::Point(50, 50), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 255), 2, 8);
cv::namedWindow("out", cv::WINDOW_FREERATIO);
cv::imshow("out", src);
cv::waitKey(0);
return 0;

}

std::vectorstd::string readClassNames() { //读取文件

std::vector<std::string> classNames;
std::ifstream fp(labels_txt_file);
if (!fp.is_open()) {printf("could not open file...\n");exit(-1);
}
std::string name;
while (!fp.eof()) {  //eof()函数判断是否读到文件末尾std::getline(fp, name);  //逐行读取文件并保存在变量中if (name.length()) {classNames.push_back(name);}
}
fp.close();
return classNames;

}
效果:

4、车辆检测与车牌识别
模型介绍
vehicle - license - plate - detection - varrier - 0106
基于BIT-Vehicle数据集
输入 1 * 3 * 300 * 300 = NCHW
输出格式:[1, 1, N, 7]
七个值:[image_id, label, conf, x_min, y_min, x_max, y_max]
调用流程
加载模型
设置输入输出
构建输入
执行推断
解析输出
显示结果
车辆及车牌检测模型下载
cd C:\Program Files (x86)\Intel\openvino_2021.2.185\deployment_tools\open_model_zoo\tools\downloader #以管理员身份运行cmd,切换到downloader文件夹下

python downloader.py --name vehicle-license-plate-detection-barrier-0106 #在该文件夹下执行该脚本,下载模型
出现下图代表下载成功:

将下载的模型文件移动到模型文件夹中:

车辆及车牌检测代码实现
#include <inference_engine.hpp>
#include <opencv2/opencv.hpp>
#include //fstream文件读写操作,iostream为控制台操作

using namespace InferenceEngine;

int main(int argc, char** argv) {

InferenceEngine::Core ie;
std::vector<std::string> devices = ie.GetAvailableDevices();
for (std::string name : devices) {std::cout << "device name: " << name << std::endl;
}
std::string cpuName = ie.GetMetric("CPU", METRIC_KEY(FULL_DEVICE_NAME)).as<std::string>();
std::cout << "cpu name: " << cpuName << std::endl;std::string xml = "D:/projects/models/vehicle-license-plate-detection-barrier-0106/FP32/vehicle-license-plate-detection-barrier-0106.xml";
std::string bin = "D:/projects/models/vehicle-license-plate-detection-barrier-0106/FP32/vehicle-license-plate-detection-barrier-0106.bin";
cv::Mat src = cv::imread("D:/images/car_1.bmp");  //读取图像
int im_h = src.rows;
int im_w = src.cols;
InferenceEngine::CNNNetwork network = ie.ReadNetwork(xml, bin);  //读取resnet18网络InferenceEngine::InputsDataMap inputs = network.getInputsInfo();  //DataMap是一个Mat数组
InferenceEngine::OutputsDataMap outputs = network.getOutputsInfo();  //DataMap是一个Mat数组
std::string input_name = "";
for (auto item : inputs) {  //auto可以自动推断变量类型input_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto input_data = item.second;input_data->setPrecision(Precision::U8);  //默认为unsigned char对应U8input_data->setLayout(Layout::NCHW);//input_data->getPreProcess().setColorFormat(ColorFormat::BGR);  默认就是BGRstd::cout << "input name: " << input_name << std::endl;
}
std::string output_name = "";
for (auto item : outputs) {  //auto可以自动推断变量类型output_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto output_data = item.second;output_data->setPrecision(Precision::FP32);  //输出还是浮点数//注意:output_data不要设置结构std::cout << "output name: " << output_name << std::endl;
}auto executable_network = ie.LoadNetwork(network, "CPU");  //设置运行的设备
auto infer_request = executable_network.CreateInferRequest();  //设置推理请求//图像预处理
auto input = infer_request.GetBlob(input_name);  //获取网络输入图像信息
size_t num_channels = input->getTensorDesc().getDims()[1];  //size_t 类型表示C中任何对象所能达到的最大长度,它是无符号整数
size_t h = input->getTensorDesc().getDims()[2];
size_t w = input->getTensorDesc().getDims()[3];
size_t image_size = h * w;
cv::Mat blob_image;
cv::resize(src, blob_image, cv::Size(w, h));  //将输入图片大小转换为与网络输入大小一致
//cv::cvtColor(blob_image, blob_image, cv::COLOR_BGR2RGB);  //色彩空间转换// HWC =》NCHW  将输入图像从HWC格式转换为NCHW格式
unsigned char* data = static_cast<unsigned char*>(input->buffer());  //将图像放到buffer中,放入input中
for (size_t row = 0; row < h; row++) {for (size_t col = 0; col < w; col++) {for (size_t ch = 0; ch < num_channels; ch++) {//将每个通道变成一张图,按照通道顺序data[image_size * ch + row * w + col] = blob_image.at<cv::Vec3b>(row, col)[ch];}}
}infer_request.Infer();
auto output = infer_request.GetBlob(output_name);
//转换输出数据
const float* detection_out = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(output->buffer());
//output:[1, 1, N, 7]
//七个参数为:[image_id, label, conf, x_min, y_min, x_max, y_max]
const SizeVector outputDims = output->getTensorDesc().getDims();  //获取输出维度信息 1*1000
std::cout << outputDims[2] << "x" << outputDims[3] << std::endl;
const int max_count = outputDims[2];  //识别出的对象个数
const int object_size = outputDims[3];  //获取对象信息的个数,此处为7个
for (int n = 0; n < max_count; n++) {float label = detection_out[n * object_size + 1];float confidence = detection_out[n * object_size + 2];float xmin = detection_out[n * object_size + 3] * im_w;float ymin = detection_out[n * object_size + 4] * im_h;float xmax = detection_out[n * object_size + 5] * im_w;float ymax = detection_out[n * object_size + 6] * im_h;if (confidence > 0.5) {printf("label id: %d \n", static_cast<int>(label));cv::Rect box;box.x = static_cast<int>(xmin);box.y = static_cast<int>(ymin);box.width = static_cast<int>(xmax - xmin);box.height = static_cast<int>(ymax - ymin);cv::rectangle(src, box, cv::Scalar(0, 0, 255), 2, 8);//box.tl()返回矩形左上角坐标cv::putText(src, cv::format("%.2f", confidence), box.tl(), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 255), 2, 8);}
}//cv::putText(src, labels[max_index], cv::Point(50, 50), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 255), 2, 8);
cv::namedWindow("out", cv::WINDOW_FREERATIO);
cv::imshow("out", src);
cv::waitKey(0);
return 0;

}
效果:

车牌识别
模型名称:license-plate-recognition-barrier-0001
输入格式:BGR
1 * 3 * 24 * 94,88 * 1 = [0, 1, 1, 1, 1, … , 1]
输出格式:1 * 88 * 1 * 1
下载模型(license-plate-recognition-barrier-0001),下载方法同上,实现思路:1初始化车牌识别网络,提升输入输出值的应用范围;2调用车辆及车牌检测模型进行车牌检测;3将车牌检测的数据输入车牌识别函数,使用车牌识别网络初始化的输入输出值在该函数中进行识别,输出识别到的车牌信息。

车牌识别代码实现
#include <opencv2/opencv.hpp>
#include <inference_engine.hpp>
#include

using namespace InferenceEngine;
static std::vectorstd::string items = {
“0”,“1”,“2”,“3”,“4”,“5”,“6”,“7”,“8”,“9”,
“< Anhui >”,“< Beijing >”,“< Chongqing >”,“< Fujian >”,
“< Gansu >”,“< Guangdong >”,“< Guangxi >”,“< Guizhou >”,
“< Hainan >”,“< Hebei >”,“< Heilongjiang >”,“< Henan >”,
“< HongKong >”,“< Hubei >”,“< Hunan >”,“< InnerMongolia >”,
“< Jiangsu >”,“< Jiangxi >”,“< Jilin >”,“< Liaoning >”,
“< Macau >”,“< Ningxia >”,“< Qinghai >”,“< Shaanxi >”,
“< Shandong >”,“< Shanghai >”,“< Shanxi >”,“< Sichuan >”,
“< Tianjin >”,“< Tibet >”,“< Xinjiang >”,“< Yunnan >”,
“< Zhejiang >”,“< police >”,
“A”,“B”,“C”,“D”,“E”,“F”,“G”,“H”,“I”,“J”,
“K”,“L”,“M”,“N”,“O”,“P”,“Q”,“R”,“S”,“T”,
“U”,“V”,“W”,“X”,“Y”,“Z”
};

InferenceEngine::InferRequest plate_request;
std::string plate_input_name1;
std::string plate_input_name2;
std::string plate_output_name;

void load_plate_recog_model();
void fetch_plate_text(cv::Mat &image, cv::Mat &plateROI);

int main(int argc, char** argv) {

InferenceEngine::Core ie;
load_plate_recog_model();  //调用车牌识别模型,模型信息保存到plate_input_name1/name2/output_name中std::string xml = "D:/projects/models/vehicle-license-plate-detection-barrier-0106/FP32/vehicle-license-plate-detection-barrier-0106.xml";
std::string bin = "D:/projects/models/vehicle-license-plate-detection-barrier-0106/FP32/vehicle-license-plate-detection-barrier-0106.bin";
cv::Mat src = cv::imread("D:/images/car_1.bmp");  //读取图像
int im_h = src.rows;
int im_w = src.cols;
InferenceEngine::CNNNetwork network = ie.ReadNetwork(xml, bin);  //读取resnet18网络InferenceEngine::InputsDataMap inputs = network.getInputsInfo();  //DataMap是一个Mat数组
InferenceEngine::OutputsDataMap outputs = network.getOutputsInfo();  //DataMap是一个Mat数组
std::string input_name = "";
for (auto item : inputs) {  //auto可以自动推断变量类型input_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto input_data = item.second;input_data->setPrecision(Precision::U8);  //默认为unsigned char对应U8input_data->setLayout(Layout::NCHW);//input_data->getPreProcess().setColorFormat(ColorFormat::BGR);  默认就是BGRstd::cout << "input name: " << input_name << std::endl;
}
std::string output_name = "";
for (auto item : outputs) {  //auto可以自动推断变量类型output_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto output_data = item.second;output_data->setPrecision(Precision::FP32);  //输出还是浮点数//注意:output_data不要设置结构std::cout << "output name: " << output_name << std::endl;
}auto executable_network = ie.LoadNetwork(network, "CPU");  //设置运行的设备
auto infer_request = executable_network.CreateInferRequest();  //设置推理请求//图像预处理
auto input = infer_request.GetBlob(input_name);  //获取网络输入图像信息
size_t num_channels = input->getTensorDesc().getDims()[1];  //size_t 类型表示C中任何对象所能达到的最大长度,它是无符号整数
size_t h = input->getTensorDesc().getDims()[2];
size_t w = input->getTensorDesc().getDims()[3];
size_t image_size = h * w;
cv::Mat blob_image;
cv::resize(src, blob_image, cv::Size(w, h));  //将输入图片大小转换为与网络输入大小一致
//cv::cvtColor(blob_image, blob_image, cv::COLOR_BGR2RGB);  //色彩空间转换// HWC =》NCHW  将输入图像从HWC格式转换为NCHW格式
unsigned char* data = static_cast<unsigned char*>(input->buffer());  //将图像放到buffer中,放入input中
for (size_t row = 0; row < h; row++) {for (size_t col = 0; col < w; col++) {for (size_t ch = 0; ch < num_channels; ch++) {//将每个通道变成一张图,按照通道顺序data[image_size * ch + row * w + col] = blob_image.at<cv::Vec3b>(row, col)[ch];}}
}infer_request.Infer();
auto output = infer_request.GetBlob(output_name);
//转换输出数据
const float* detection_out = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(output->buffer());
//output:[1, 1, N, 7]
//七个参数为:[image_id, label, conf, x_min, y_min, x_max, y_max]
const SizeVector outputDims = output->getTensorDesc().getDims();  //获取输出维度信息 1*1000
std::cout << outputDims[2] << "x" << outputDims[3] << std::endl;
const int max_count = outputDims[2];  //识别出的对象个数
const int object_size = outputDims[3];  //获取对象信息的个数,此处为7个
for (int n = 0; n < max_count; n++) {float label = detection_out[n * object_size + 1];float confidence = detection_out[n * object_size + 2];float xmin = detection_out[n * object_size + 3] * im_w;float ymin = detection_out[n * object_size + 4] * im_h;float xmax = detection_out[n * object_size + 5] * im_w;float ymax = detection_out[n * object_size + 6] * im_h;if (confidence > 0.5) {printf("label id: %d \n", static_cast<int>(label));cv::Rect box;box.x = static_cast<int>(xmin);box.y = static_cast<int>(ymin);box.width = static_cast<int>(xmax - xmin);box.height = static_cast<int>(ymax - ymin);if (label == 2) {  //将车牌用绿色表示cv::rectangle(src, box, cv::Scalar(0, 255, 0), 2, 8);//recognize platecv::Rect plate_roi;plate_roi.x = box.x - 5;plate_roi.y = box.y - 5;plate_roi.width = box.width + 10;plate_roi.height = box.height + 10;cv::Mat roi = src(plate_roi);  //需要先初始化Mat&,才能使用//调用车牌识别方法fetch_plate_text(src, roi);}else {cv::rectangle(src, box, cv::Scalar(0, 0, 255), 2, 8);}//box.tl()返回矩形左上角坐标cv::putText(src, cv::format("%.2f", confidence), box.tl(), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 255), 2, 8);}
}//cv::putText(src, labels[max_index], cv::Point(50, 50), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 255), 2, 8);
cv::namedWindow("out", cv::WINDOW_FREERATIO);
cv::imshow("out", src);
cv::waitKey(0);
return 0;

}

void load_plate_recog_model() {
InferenceEngine::Core ie;

std::string xml = "D:/projects/models/license-plate-recognition-barrier-0001/FP32/license-plate-recognition-barrier-0001.xml";
std::string bin = "D:/projects/models/license-plate-recognition-barrier-0001/FP32/license-plate-recognition-barrier-0001.bin";InferenceEngine::CNNNetwork network = ie.ReadNetwork(xml, bin);  //读取网络
InferenceEngine::InputsDataMap inputs = network.getInputsInfo();  //DataMap是一个Mat数组
InferenceEngine::OutputsDataMap outputs = network.getOutputsInfo();  //DataMap是一个Mat数组int cnt = 0;
for (auto item : inputs) {  //auto可以自动推断变量类型if (cnt == 0) {plate_input_name1 = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto input_data = item.second;input_data->setPrecision(Precision::U8);  //默认为unsigned char对应U8input_data->setLayout(Layout::NCHW);}else if (cnt == 1) {plate_input_name2 = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto input_data = item.second;input_data->setPrecision(Precision::FP32);  //默认为unsigned char对应U8}//input_data->getPreProcess().setColorFormat(ColorFormat::BGR);  默认就是BGRstd::cout << "input name: " << (cnt + 1) << ":" << item.first << std::endl;cnt++;
}
std::string output_name = "";
for (auto item : outputs) {  //auto可以自动推断变量类型plate_output_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto output_data = item.second;output_data->setPrecision(Precision::FP32);  //输出还是浮点数//注意:output_data不要设置结构std::cout << "output name: " << plate_output_name << std::endl;
}auto executable_network = ie.LoadNetwork(network, "CPU");  //设置运行的设备
plate_request = executable_network.CreateInferRequest();  //设置推理请求

}

void fetch_plate_text(cv::Mat &image, cv::Mat &plateROI) {
//图像预处理,使用车牌识别的方法中获取的输入输出信息,用于文本获取
auto input1 = plate_request.GetBlob(plate_input_name1); //获取网络输入图像信息
size_t num_channels = input1->getTensorDesc().getDims()[1]; //size_t 类型表示C中任何对象所能达到的最大长度,它是无符号整数
size_t h = input1->getTensorDesc().getDims()[2];
size_t w = input1->getTensorDesc().getDims()[3];
size_t image_size = h * w;
cv::Mat blob_image;
cv::resize(plateROI, blob_image, cv::Size(94, 24)); //将输入图片大小转换为与网络输入大小一致
//cv::cvtColor(blob_image, blob_image, cv::COLOR_BGR2RGB); //色彩空间转换

// HWC =》NCHW  将输入图像从HWC格式转换为NCHW格式
unsigned char* data = static_cast<unsigned char*>(input1->buffer());  //将图像放到buffer中,放入input中
for (size_t row = 0; row < h; row++) {for (size_t col = 0; col < w; col++) {for (size_t ch = 0; ch < num_channels; ch++) {//将每个通道变成一张图,按照通道顺序data[image_size * ch + row * w + col] = blob_image.at<cv::Vec3b>(row, col)[ch];}}
}//使用车牌识别的方法中获取的输入输出信息,用于文本获取
auto input2 = plate_request.GetBlob(plate_input_name2);
int max_sequence = input2->getTensorDesc().getDims()[0];  //输出字符长度
float* blob2 = input2->buffer().as<float*>();
blob2[0] = 0.0;
std::fill(blob2 + 1, blob2 + max_sequence, 1.0f);  //填充起止范围与填充值plate_request.Infer();  //执行推理
auto output = plate_request.GetBlob(plate_output_name);  //获取推理结果
const float* plate_data = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(output->buffer());  //获取浮点类型输出值plate_data
std::string result;
for (int i = 0; i < max_sequence; i++) {if (plate_data[i] == -1) {  //endbreak;}result += items[std::size_t(plate_data[i])];  //类型转换,字符串拼接
}
std::cout << result << std::endl;
cv::putText(image, result.c_str(), cv::Point(50, 50), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 255), 2, 8);

}
效果:

5、行人检测、人脸检测及表情识别
视频行人检测
模型介绍
pedestrian-detection-adas-0002
SSD MobileNetv1
输入格式:[1 * 3 * 384 * 672]
输出格式:[1, 1, N, 7]
代码实现
#include <inference_engine.hpp>
#include <opencv2/opencv.hpp>
#include //fstream文件读写操作,iostream为控制台操作

using namespace InferenceEngine;
void infer_process(cv::Mat &frame, InferenceEngine::InferRequest &request, std::string &input_name, std::string &output_name);
int main(int argc, char** argv) {

InferenceEngine::Core ie;std::string xml = "D:/projects/models/pedestrian-detection-adas-0002/FP32/pedestrian-detection-adas-0002.xml";
std::string bin = "D:/projects/models/pedestrian-detection-adas-0002/FP32/pedestrian-detection-adas-0002.bin";
cv::Mat src = cv::imread("D:/images/pedestrians_test.jpg");  //读取图像
int im_h = src.rows;
int im_w = src.cols;
InferenceEngine::CNNNetwork network = ie.ReadNetwork(xml, bin);  //读取车辆检测网络//获取网络输入输出信息
InferenceEngine::InputsDataMap inputs = network.getInputsInfo();  //DataMap是一个Mat数组
InferenceEngine::OutputsDataMap outputs = network.getOutputsInfo();  //DataMap是一个Mat数组
std::string input_name = "";
for (auto item : inputs) {  //auto可以自动推断变量类型input_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto input_data = item.second;// A->B 表示提取A中的成员Binput_data->setPrecision(Precision::U8);  //默认为unsigned char对应U8input_data->setLayout(Layout::NCHW);//input_data->getPreProcess().setColorFormat(ColorFormat::BGR);  默认就是BGRstd::cout << "input name: " << input_name << std::endl;
}
std::string output_name = "";
for (auto item : outputs) {  //auto可以自动推断变量类型output_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto output_data = item.second;output_data->setPrecision(Precision::FP32);  //输出还是浮点数//注意:output_data不要设置结构std::cout << "output name: " << output_name << std::endl;
}auto executable_network = ie.LoadNetwork(network, "CPU");  //设置运行的设备
auto infer_request = executable_network.CreateInferRequest();  //设置推理请求//创建视频流/加载视频文件
cv::VideoCapture capture("D:/images/video/pedestrians_test.mp4");
cv::Mat frame;
while (true) {bool ret = capture.read(frame);if (!ret) {  //视频帧为空就跳出循环break;}infer_process(frame, infer_request, input_name, output_name);cv::imshow("frame", frame);char c = cv::waitKey(1);if (c == 27) {  //ESCbreak;}
}//cv::putText(src, labels[max_index], cv::Point(50, 50), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 255), 2, 8);
cv::namedWindow("out", cv::WINDOW_FREERATIO);
cv::imshow("out", src);
cv::waitKey(0);  //最后的视频画面静止
return 0;

}

void infer_process(cv::Mat& frame, InferenceEngine::InferRequest& request, std::string& input_name, std::string& output_name) {
//图像预处理
auto input = request.GetBlob(input_name); //获取网络输入图像信息
int im_w = frame.cols;
int im_h = frame.rows;
size_t num_channels = input->getTensorDesc().getDims()[1]; //size_t 类型表示C中任何对象所能达到的最大长度,它是无符号整数
size_t h = input->getTensorDesc().getDims()[2];
size_t w = input->getTensorDesc().getDims()[3];
size_t image_size = h * w;
cv::Mat blob_image;
cv::resize(frame, blob_image, cv::Size(w, h)); //将输入图片大小转换为与网络输入大小一致
//cv::cvtColor(blob_image, blob_image, cv::COLOR_BGR2RGB); //色彩空间转换

// HWC =》NCHW  将输入图像从HWC格式转换为NCHW格式
unsigned char* data = static_cast<unsigned char*>(input->buffer());  //将图像放到buffer中,放入input中
for (size_t row = 0; row < h; row++) {for (size_t col = 0; col < w; col++) {for (size_t ch = 0; ch < num_channels; ch++) {//将每个通道变成一张图,按照通道顺序data[image_size * ch + row * w + col] = blob_image.at<cv::Vec3b>(row, col)[ch];}}
}request.Infer();
auto output = request.GetBlob(output_name);
//转换输出数据
const float* detection_out = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(output->buffer());
//output:[1, 1, N, 7]
//七个参数为:[image_id, label, conf, x_min, y_min, x_max, y_max]
const SizeVector outputDims = output->getTensorDesc().getDims();  //获取输出维度信息 1*1000
std::cout << outputDims[2] << "x" << outputDims[3] << std::endl;
const int max_count = outputDims[2];  //识别出的对象个数
const int object_size = outputDims[3];  //获取对象信息的个数,此处为7个
for (int n = 0; n < max_count; n++) {float label = detection_out[n * object_size + 1];float confidence = detection_out[n * object_size + 2];float xmin = detection_out[n * object_size + 3] * im_w;float ymin = detection_out[n * object_size + 4] * im_h;float xmax = detection_out[n * object_size + 5] * im_w;float ymax = detection_out[n * object_size + 6] * im_h;if (confidence > 0.9) {printf("label id: %d \n", static_cast<int>(label));cv::Rect box;box.x = static_cast<int>(xmin);box.y = static_cast<int>(ymin);box.width = static_cast<int>(xmax - xmin);box.height = static_cast<int>(ymax - ymin);if (label == 2) {  //将车牌与车辆用不同颜色表示cv::rectangle(frame, box, cv::Scalar(0, 255, 0), 2, 8);}else {cv::rectangle(frame, box, cv::Scalar(0, 0, 255), 2, 8);}//cv::rectangle(src, box, cv::Scalar(0, 0, 255), 2, 8);//box.tl()返回矩形左上角坐标cv::putText(frame, cv::format("%.2f", confidence), box.tl(), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 255), 2, 8);}
}

}
效果:

实时人脸检测之异步推理
模型介绍
人脸检测:face-detection-0202,SSD-MobileNetv2
输入格式:1 * 3 * 384 * 384
输出格式:[1, 1, N, 7]
OpenVINO中人脸检测模型0202~0206
同步与异步执行

代码实现
#include <inference_engine.hpp>
#include <opencv2/opencv.hpp>
#include //fstream文件读写操作,iostream为控制台操作

using namespace InferenceEngine;

//图像预处理函数
template
void matU8ToBlob(const cv::Mat& orig_image, InferenceEngine::Blob::Ptr& blob, int batchIndex = 0) {
InferenceEngine::SizeVector blobSize = blob->getTensorDesc().getDims();
const size_t width = blobSize[3];
const size_t height = blobSize[2];
const size_t channels = blobSize[1];
InferenceEngine::MemoryBlob::Ptr mblob = InferenceEngine::asInferenceEngine::MemoryBlob(blob);
if (!mblob) {
THROW_IE_EXCEPTION << "We expect blob to be inherited from MemoryBlob in matU8ToBlob, "
<< “but by fact we were not able to cast inputBlob to MemoryBlob”;
}
// locked memory holder should be alive all time while access to its buffer happens
auto mblobHolder = mblob->wmap();

T* blob_data = mblobHolder.as<T*>();cv::Mat resized_image(orig_image);
if (static_cast<int>(width) != orig_image.size().width ||static_cast<int>(height) != orig_image.size().height) {cv::resize(orig_image, resized_image, cv::Size(width, height));
}int batchOffset = batchIndex * width * height * channels;for (size_t c = 0; c < channels; c++) {for (size_t h = 0; h < height; h++) {for (size_t w = 0; w < width; w++) {blob_data[batchOffset + c * width * height + h * width + w] =resized_image.at<cv::Vec3b>(h, w)[c];}}
}

}

void frameToBlob(std::shared_ptrInferenceEngine::InferRequest& request, cv::Mat& frame, std::string& input_name) {
//图像预处理,输入数据 ->指针获取成员方法
InferenceEngine::Blob::Ptr input = request->GetBlob(input_name); //获取网络输入图像信息
//该函数template模板类型,需要指定具体类型
matU8ToBlob(frame, input); //使用该函数处理输入数据
}

int main(int argc, char** argv) {

InferenceEngine::Core ie;
std::vector<std::string> devices = ie.GetAvailableDevices();
for (std::string name : devices) {std::cout << "device name: " << name << std::endl;
}
std::string cpuName = ie.GetMetric("CPU", METRIC_KEY(FULL_DEVICE_NAME)).as<std::string>();
std::cout << "cpu name: " << cpuName << std::endl;std::string xml = "D:/projects/models/face-detection-0202/FP32/face-detection-0202.xml";
std::string bin = "D:/projects/models/face-detection-0202/FP32/face-detection-0202.bin";//cv::Mat src = cv::imread("D:/images/mmc2.jpg");  //读取图像
//int im_h = src.rows;
//int im_w = src.cols;InferenceEngine::CNNNetwork network = ie.ReadNetwork(xml, bin);  //读取车辆检测网络//获取网络输入输出信息并设置
InferenceEngine::InputsDataMap inputs = network.getInputsInfo();  //DataMap是一个Mat数组
InferenceEngine::OutputsDataMap outputs = network.getOutputsInfo();  //DataMap是一个Mat数组
std::string input_name = "";
for (auto item : inputs) {  //auto可以自动推断变量类型input_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto input_data = item.second;// A->B 表示提取A中的成员Binput_data->setPrecision(Precision::U8);  //默认为unsigned char对应U8input_data->setLayout(Layout::NCHW);//input_data->getPreProcess().setColorFormat(ColorFormat::BGR);  默认就是BGRstd::cout << "input name: " << input_name << std::endl;
}
std::string output_name = "";
for (auto item : outputs) {  //auto可以自动推断变量类型output_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto output_data = item.second;output_data->setPrecision(Precision::FP32);  //输出还是浮点数//注意:output_data不要设置结构std::cout << "output name: " << output_name << std::endl;
}auto executable_network = ie.LoadNetwork(network, "CPU");  //设置运行的设备
//创建指针类型便于后续操作
auto curr_infer_request = executable_network.CreateInferRequestPtr();  //设置推理请求
auto next_infer_request = executable_network.CreateInferRequestPtr();  //设置推理请求cv::VideoCapture capture("D:/images/video/pedestrians_test.mp4");
cv::Mat curr_frame;
cv::Mat next_frame;
capture.read(curr_frame);  //先读取一帧作为当前帧
int im_h = curr_frame.rows;
int im_w = curr_frame.cols;
frameToBlob(curr_infer_request, curr_frame, input_name);
bool first_frame = true;  //设置两个bool变量控制线程开启
bool last_frame = false;
//开启两个线程,curr转换显示结果,next预处理图像,预处理后交换给curr
while (true) {int64 start = cv::getTickCount();  //计时bool ret = capture.read(next_frame);  //读取一帧作为下一帧if (!ret) {last_frame = true;  //如果下一帧为空,则last_frame为true}if (!last_frame) {  //如果last_frame为false则预处理下一帧图像frameToBlob(next_infer_request, next_frame, input_name);}if (first_frame) {  //如果first_frame为true则开启两个线程,同时修改first_frame为false,避免多次开启线程curr_infer_request->StartAsync();  //开启线程next_infer_request->StartAsync();first_frame = false;}else {  //如果first_frame与last_frame同为false表示只有下一帧不为空,则开启一个next线程if (!last_frame) {next_infer_request->StartAsync();}}//判断当前请求是否预处理完毕if (InferenceEngine::OK == curr_infer_request->Wait(InferenceEngine::IInferRequest::WaitMode::RESULT_READY)) {auto output = curr_infer_request->GetBlob(output_name);//转换输出数据const float* detection_out = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(output->buffer());//output:[1, 1, N, 7]//七个参数为:[image_id, label, conf, x_min, y_min, x_max, y_max]const SizeVector outputDims = output->getTensorDesc().getDims();  //获取输出维度信息 1*1000std::cout << outputDims[2] << "x" << outputDims[3] << std::endl;const int max_count = outputDims[2];  //识别出的对象个数const int object_size = outputDims[3];  //获取对象信息的个数,此处为7个for (int n = 0; n < max_count; n++) {float label = detection_out[n * object_size + 1];float confidence = detection_out[n * object_size + 2];float xmin = detection_out[n * object_size + 3] * im_w;float ymin = detection_out[n * object_size + 4] * im_h;float xmax = detection_out[n * object_size + 5] * im_w;float ymax = detection_out[n * object_size + 6] * im_h;if (confidence > 0.5) {printf("label id: %d \n", static_cast<int>(label));cv::Rect box;box.x = static_cast<int>(xmin);box.y = static_cast<int>(ymin);box.width = static_cast<int>(xmax - xmin);box.height = static_cast<int>(ymax - ymin);cv::rectangle(curr_frame, box, cv::Scalar(0, 0, 255), 2, 8);//getTickCount()相减得到cpu走过的时钟周期数,getTickFrequency()得到cpu一秒走过的始终周期数float t = (cv::getTickCount() - start) / static_cast<float>(cv::getTickFrequency());std::cout << 1.0 / t << std::endl;//box.tl()返回矩形左上角坐标cv::putText(curr_frame, cv::format("%.2f", confidence), box.tl(), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 255), 2, 8);}}}//显示结果cv::imshow("人脸检测异步显示", curr_frame);char c = cv::waitKey(1);if (c == 27) {  //ESCbreak;}if (last_frame) {  //如果last_frame为true表示下一帧为空,则跳出循环break;}//异步交换,下一帧复制到当前帧,当前帧请求与下一帧请求交换next_frame.copyTo(curr_frame);curr_infer_request.swap(next_infer_request);  //指针可以使用swap方法,否则不行
}cv::waitKey(0);
return 0;

}
效果:

实时人脸表情识别
模型介绍
人脸检测:face-detection-0202,SSD-MobileNetv2
输入格式:1 * 3 * 384 * 384
输出格式:[1, 1, N, 7]
表情识别:emotions-recognition-retail-0003
1 * 3 * 64 * 64
[1, 5, 1, 1] - (‘neutral’, ‘happy’, ‘sad’, ‘suprise’, ‘anger’)
下载模型 emotions-recognition-retail-0003 同前
同步与异步执行

代码实现
#include <inference_engine.hpp>
#include <opencv2/opencv.hpp>
#include //fstream文件读写操作,iostream为控制台操作

using namespace InferenceEngine;

static const char *const items[] = {
“neutral”,“happy”,“sad”,“surprise”,“anger”
};

//图像预处理函数
template
void matU8ToBlob(const cv::Mat& orig_image, InferenceEngine::Blob::Ptr& blob, int batchIndex = 0) {
InferenceEngine::SizeVector blobSize = blob->getTensorDesc().getDims();
const size_t width = blobSize[3];
const size_t height = blobSize[2];
const size_t channels = blobSize[1];
InferenceEngine::MemoryBlob::Ptr mblob = InferenceEngine::asInferenceEngine::MemoryBlob(blob);
if (!mblob) {
THROW_IE_EXCEPTION << "We expect blob to be inherited from MemoryBlob in matU8ToBlob, "
<< “but by fact we were not able to cast inputBlob to MemoryBlob”;
}
// locked memory holder should be alive all time while access to its buffer happens
auto mblobHolder = mblob->wmap();

T* blob_data = mblobHolder.as<T*>();cv::Mat resized_image(orig_image);
if (static_cast<int>(width) != orig_image.size().width ||static_cast<int>(height) != orig_image.size().height) {cv::resize(orig_image, resized_image, cv::Size(width, height));
}int batchOffset = batchIndex * width * height * channels;for (size_t c = 0; c < channels; c++) {for (size_t h = 0; h < height; h++) {for (size_t w = 0; w < width; w++) {blob_data[batchOffset + c * width * height + h * width + w] =resized_image.at<cv::Vec3b>(h, w)[c];}}
}

}

void fetch_emotion(cv::Mat& image, InferenceEngine::InferRequest& request, cv::Rect& face_roi, std::string& e_input, std::string& e_output);
void frameToBlob(std::shared_ptrInferenceEngine::InferRequest& request, cv::Mat& frame, std::string& input_name) {
//图像预处理,输入数据 ->指针获取成员方法
InferenceEngine::Blob::Ptr input = request->GetBlob(input_name); //获取网络输入图像信息
//该函数template模板类型,需要指定具体类型
matU8ToBlob(frame, input); //使用该函数处理输入数据
}

int main(int argc, char** argv) {

InferenceEngine::Core ie;//load face model
std::string xml = "D:/projects/models/face-detection-0202/FP32/face-detection-0202.xml";
std::string bin = "D:/projects/models/face-detection-0202/FP32/face-detection-0202.bin";
InferenceEngine::CNNNetwork network = ie.ReadNetwork(xml, bin);  //读取车辆检测网络
//获取网络输入输出信息并设置
InferenceEngine::InputsDataMap inputs = network.getInputsInfo();  //DataMap是一个Mat数组
InferenceEngine::OutputsDataMap outputs = network.getOutputsInfo();  //DataMap是一个Mat数组std::string input_name = "";
for (auto item : inputs) {  //auto可以自动推断变量类型input_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto input_data = item.second;// A->B 表示提取A中的成员Binput_data->setPrecision(Precision::U8);  //默认为unsigned char对应U8input_data->setLayout(Layout::NCHW);//input_data->getPreProcess().setColorFormat(ColorFormat::BGR);  默认就是BGRstd::cout << "input name: " << input_name << std::endl;
}
std::string output_name = "";
for (auto item : outputs) {  //auto可以自动推断变量类型output_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto output_data = item.second;output_data->setPrecision(Precision::FP32);  //输出还是浮点数//注意:output_data不要设置结构std::cout << "output name: " << output_name << std::endl;
}auto executable_network = ie.LoadNetwork(network, "CPU");  //设置运行的设备
//创建指针类型便于后续操作
auto curr_infer_request = executable_network.CreateInferRequestPtr();  //设置推理请求
auto next_infer_request = executable_network.CreateInferRequestPtr();  //设置推理请求//load emotion model
std::string em_xml = "D:/projects/models/emotions-recognition-retail-0003/FP32/emotions-recognition-retail-0003.xml";
std::string em_bin = "D:/projects/models/emotions-recognition-retail-0003/FP32/emotions-recognition-retail-0003.bin";
InferenceEngine::CNNNetwork em_network = ie.ReadNetwork(em_xml, em_bin);  //读取车辆检测网络
//获取网络输入输出信息并设置
InferenceEngine::InputsDataMap em_inputs = em_network.getInputsInfo();  //DataMap是一个Mat数组
InferenceEngine::OutputsDataMap em_outputs = em_network.getOutputsInfo();  //DataMap是一个Mat数组std::string em_input_name = "";
for (auto item : em_inputs) {em_input_name = item.first;//循环作用域内的变量可以不重命名,为查看更明确这里重命名auto em_input_data = item.second;em_input_data->setPrecision(Precision::U8);em_input_data->setLayout(Layout::NCHW);
}
std::string em_output_name = "";
for (auto item : em_outputs) {  //auto可以自动推断变量类型em_output_name = item.first;  //第一个参数是name,第二个参数是结构,第二个参数设置精度与结构auto em_output_data = item.second;em_output_data->setPrecision(Precision::FP32);  //输出还是浮点数
}
auto executable_em_network = ie.LoadNetwork(em_network, "CPU");  //设置运行的设备
//创建指针类型便于后续操作
auto em_request = executable_em_network.CreateInferRequest();  //设置推理请求cv::VideoCapture capture("D:/images/video/face_detect.mp4");
cv::Mat curr_frame;
cv::Mat next_frame;
capture.read(curr_frame);  //先读取一帧作为当前帧
int im_h = curr_frame.rows;
int im_w = curr_frame.cols;
frameToBlob(curr_infer_request, curr_frame, input_name);
bool first_frame = true;  //设置两个bool变量控制线程开启
bool last_frame = false;
//开启两个线程,curr转换显示结果,next预处理图像,预处理后交换给curr
while (true) {int64 start = cv::getTickCount();  //计时bool ret = capture.read(next_frame);  //读取一帧作为下一帧if (!ret) {last_frame = true;  //如果下一帧为空,则last_frame为true}if (!last_frame) {  //如果last_frame为false则预处理下一帧图像frameToBlob(next_infer_request, next_frame, input_name);}if (first_frame) {  //如果first_frame为true则开启两个线程,同时修改first_frame为false,避免多次开启线程curr_infer_request->StartAsync();  //开启线程next_infer_request->StartAsync();first_frame = false;}else {  //如果first_frame与last_frame同为false表示只有下一帧不为空,则开启一个next线程if (!last_frame) {next_infer_request->StartAsync();}}//判断当前请求是否预处理完毕if (InferenceEngine::OK == curr_infer_request->Wait(InferenceEngine::IInferRequest::WaitMode::RESULT_READY)) {auto output = curr_infer_request->GetBlob(output_name);//转换输出数据const float* detection_out = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(output->buffer());//output:[1, 1, N, 7]//七个参数为:[image_id, label, conf, x_min, y_min, x_max, y_max]const SizeVector outputDims = output->getTensorDesc().getDims();  //获取输出维度信息 1*1000std::cout << outputDims[2] << "x" << outputDims[3] << std::endl;const int max_count = outputDims[2];  //识别出的对象个数const int object_size = outputDims[3];  //获取对象信息的个数,此处为7个for (int n = 0; n < max_count; n++) {float label = detection_out[n * object_size + 1];float confidence = detection_out[n * object_size + 2];float xmin = detection_out[n * object_size + 3] * im_w;float ymin = detection_out[n * object_size + 4] * im_h;float xmax = detection_out[n * object_size + 5] * im_w;float ymax = detection_out[n * object_size + 6] * im_h;if (confidence > 0.5) {printf("label id: %d \n", static_cast<int>(label));cv::Rect box;box.x = static_cast<int>(xmin);box.y = static_cast<int>(ymin);xmax = xmax > im_w ? im_w : xmax;  //通过判断避免越界ymax = ymax > im_h ? im_h : ymax;box.width = static_cast<int>(xmax - xmin);box.height = static_cast<int>(ymax - ymin);box.x = box.x < 0 ? 0 : box.x;  //通过判断避免越界box.y = box.y < 0 ? 0 : box.y;box.width = box.x < 0 ? 0 : box.width;box.height = box.x < 0 ? 0 : box.height;cv::rectangle(curr_frame, box, cv::Scalar(0, 0, 255), 2, 8);fetch_emotion(curr_frame, em_request, box, em_input_name, em_output_name);  //获取表情//getTickCount()相减得到cpu走过的时钟周期数,getTickFrequency()得到cpu一秒走过的始终周期数float fps = static_cast<float>(cv::getTickFrequency()) / (cv::getTickCount() - start);cv::putText(curr_frame, cv::format("FPS:%.2f", fps), cv::Point(50, 50), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 255), 2, 8);}}}//显示结果cv::imshow("人脸检测异步显示", curr_frame);char c = cv::waitKey(1);if (c == 27) {  //ESCbreak;}if (last_frame) {  //如果last_frame为true表示下一帧为空,则跳出循环break;}//异步交换,下一帧复制到当前帧,当前帧请求与下一帧请求交换next_frame.copyTo(curr_frame);curr_infer_request.swap(next_infer_request);  //指针可以使用swap方法,否则不行
}cv::waitKey(0);
return 0;

}

//获取表情
void fetch_emotion(cv::Mat& image, InferenceEngine::InferRequest& request, cv::Rect& face_roi, std::string& e_input, std::string& e_output) {

cv::Mat faceROI = image(face_roi);  //获取面部区域
//图像预处理,使用车牌识别的方法中获取的输入输出信息,用于文本获取
auto blob = request.GetBlob(e_input);  //获取网络输入图像信息
matU8ToBlob<uchar>(faceROI, blob);request.Infer();  //执行推理auto output = request.GetBlob(e_output);
//转换输出数据
const float* probs = static_cast<PrecisionTrait<Precision::FP32>::value_type*>(output->buffer());
const SizeVector outputDims = output->getTensorDesc().getDims();  //获取输出维度信息 1*1000
std::cout << outputDims[0] << "x" << outputDims[1] << std::endl;
float max = probs[0];
int max_index = 0;
for (int i = 1; i < outputDims[1]; i++) {if (max < probs[i]) {  //找到结果probs中的最大值,获取其下标max = probs[i];max_index = i;}
}
std::cout << items[max_index] << std::endl;
cv::putText(image, items[max_index], face_roi.tl(), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(0, 0, 255), 2, 8);

}
效果:

人脸关键点landmark检测
模型介绍
face-detection-0202 - 人脸检测
facial-landmarks-35-adas-0002 - landmark提取
输入格式:[1 * 3 * 60 * 60]
输出格式:[1, 70]
输出人脸35个特征点,浮点数坐标

程序流程

代码实现
#include <inference_engine.hpp>
#include <opencv2/opencv.hpp>
#include //fstream文件读写操作,iostream为控制台操作

using namespace InferenceEngine;

//图像预处理函数
template
void matU8ToBlob(const cv::Mat& orig_image, InferenceEngine::Blob::Ptr& blob, int batchIndex = 0) {
InferenceEngine::SizeVector blobSize = blob->getTensorDesc().getDims();
const size_t width = blobSize[3];
const size_t height = blobSize[2];
const size_t channels = blobSize[1];
InferenceEngine::MemoryBlob::Ptr mblob = InferenceEngine::asInferenceEngine::MemoryBlob(blob);
if (!mblob) {
THROW_IE_EXCEPTION << "We expect blob to be inherited from MemoryBlob in matU8ToBlob, "
<< “but by fact we were not able to cast inputBlob to MemoryBlob”;
}
// locked memory holder should be alive all time while access to its buffer happens
auto mblobHolder = mblob->wmap();

T* blob_data = mblobHolder.as<T*>();cv::Mat resized_image(orig_image);
if (static_cast<int>(width) != orig_image.size().width ||static_cast<int>(height) != orig_image.size().height) {cv::resize(orig_image, resized_image, cv::Size(width, height));
}int batchOffset = batchIndex * width * height * channels;for (size_t c = 0; c < channels; c++) {for (size_t h = 0; h < height; h++) {for (size_t w = 0; w < width; w++) {blob_data[batchOffset + c * width * height + h * width + w] =resized_image.at<cv::Vec3b>(h, w)[c];}}
}

}

void frameToBlob(std::shared_ptrInferenceEngine::InferRequest& request, cv::Mat& frame, std::string& input_name) {
//图像预处理,输入数据 ->指针获取成员方法
InferenceEngine::Blob::Ptr input = request->GetBlob(input_name); //获取网络输入图像信息
//该函数template模板类型,需要指定具体类型
matU8ToBlob(frame, input); //使用该函数处理输入数据
}

InferenceEngine::InferRequest landmark_request; //提高推理请求作用域
void loadLandmarksRequest(Core& ie, std::string& land_input_name, std::string& land_output_name);
int main(int argc, char** argv) {


http://www.ppmy.cn/news/562616.html

相关文章

基于富芮坤fr8016 蓝牙5.0 芯片设计的BLE HID Joystick 游戏摇杆设备

文章目录 ble hid 学习笔记HID报告描述符与BLE HID profile之间关系1、HID报告描述符 富芮坤fr8016 设计Joystick例子1、描述X轴Y轴Z轴2、描述按钮3、Joystick 报告描述符4、程序修改5、win10测试6、android 测试 总结 ble hid 学习笔记 HID报告描述符与BLE HID profile之间关…

2023-06-25 LeetCode每日一题(圆和矩形是否有重叠)

2023-06-25每日一题 一、题目编号 1401. 圆和矩形是否有重叠二、题目链接 点击跳转到题目位置 三、题目描述 给你一个以 (radius, xCenter, yCenter) 表示的圆和一个与坐标轴平行的矩形 (x1, y1, x2, y2) &#xff0c;其中 (x1, y1) 是矩形左下角的坐标&#xff0c;而 (x2…

【PCB专题】Allegro中设置泪滴

PCB绘制完成后有时按需要对PCB进行添加泪滴的操作是非常必要的。 添加泪滴的作用主要是: 信号传输时平滑阻抗,减少阻抗的急剧跳变,避免高频信号传输时由于线宽突然变小而造成反射。 焊接时可以保护焊盘,避免多次焊接时焊盘的脱落,生产时可以避免蚀刻不均,以及过孔偏位出…

ViewModel进阶 | 使用SavedState实现数据复用的另一种方式

前言&#xff1a;金风玉露一相逢&#xff0c;便胜人间无数。 前言 本文需要有上一篇文章基础&#xff0c;如果不了解的可以先看看《由浅入深&#xff0c;ViewModel配置变更的复用详解》 前面我们了解到&#xff0c;ViewModel 它只能做到因为配置变更页面被销毁而导致重建数据…

人工智能技术与GIS结合的发展

个人本是GIS专业出身&#xff0c;不知名985高校本硕。工作几年后先后积累了国土空间规划、cesium开发、地理信息数据采集、地理大数据处理&#xff0c;遥感影像处理、人工智能识别&#xff0c;做过十多个500万以上的相关项目&#xff0c;有一些浅薄的经验&#xff0c;想和大家分…

伪娘之男扮女装

>>伪娘 伪娘&#xff0c;是一个ACG界名词(动画、漫画、游戏)&#xff0c;通常指的是男扮女装且有女性美貌的男性角色&#xff0c;变装后常常带有很强的萌属性&#xff0c;有的可能更胜过一般女性角色&#xff0c;在日本年轻男性中正在兴起一种女装男子的“伪娘”热。聘用…

女装搭配的方法,搭配需要注意的地方

女装搭配的方法&#xff0c;搭配需要注意的地方 一、上下装的搭配 一般上浅下深的色彩搭配方式会在视觉上产生稳定与稳重的感觉服装搭配技巧&#xff0c;而上深下浅的色彩搭配方式会相对给人以活跃于轻松的感受。 1、上下装颜色相同时&#xff0c;可以选择面料质地不同的服装…

趣题:怎么从一帮女装大佬中分辨出谁是真妹子?(大雾)

尝试一篇仿m67风格的博客。 你受邀参加一场女装聚会&#xff0c;除了你和聚会组织者之外还有n个人参加&#xff0c;这些人你都不认识。 组织者告诉你&#xff1a;这场聚会上所有人都会穿女装&#xff0c;但其中有一部分是真妹子&#xff0c;另外一些则是女装大佬。 作为直男…