网站建设和咨询服务合同,博客网站开发背景,中卫网站推广公司,装饰设计收费标准前言
人像抠图将图像中的人物与背景进行像素级别的区分的技术。通过人像分割#xff0c;可以实现诸如背景虚化、弹幕穿人等各种有趣的功能#xff0c;为视频通话和影音观看提供更加优质和丰富的体验。由于广泛部署到Web、手机和边缘设备#xff0c;肖像分割在兼顾分割精度的…前言
人像抠图将图像中的人物与背景进行像素级别的区分的技术。通过人像分割可以实现诸如背景虚化、弹幕穿人等各种有趣的功能为视频通话和影音观看提供更加优质和丰富的体验。由于广泛部署到Web、手机和边缘设备肖像分割在兼顾分割精度的前提下需要具有极快的推理速度。
PP-HumanSeg v2人像分割方案是一项重要的突破采用了深度学习技术以96.63%的mIoU精度和仅15.86ms的推理耗时在人像分割领域刷新了SOTA指标。该方案不仅支持商业应用而且可零成本、开箱即用。
相比于之前的版本PP-HumanSeg v2在推理速度和精度上都有显著提升肖像分割模型推理速度提升45.5%mIoU精度提升3.03%。通用人像分割模型推理速度提升5.7%mIoU精度提升6.5%。
网络结构
PaddleSeg整体结构如下图所示。具体优化过程如下 骨干网络选择 为了降低模型的算量要求选择了MobileNetV3作为骨干网络用于提取多层特征。 参数量优化 对MobileNetV3进行参数量优化。分析发现MobileNetV3的参数主要集中在最后一个Stage在不影响分割精度的前提下保留了MobileNetV3的前四个Stage成功减少了68.6%的参数量。 全局上下文信息汇集 对于16倍下采样特征图使用了SPPMSpatial Pyramid Pooling Module模块来汇集全局上下文信息以提高模型对背景和环境的理解能力。 特征融合 使用三个Fusion模块来不断融合深层语义特征和浅层细节特征。这些Fusion模块的作用是将不同层次的特征图进行融合以获取更加丰富和准确的语义信息。 分割结果输出 最后一个Fusion模块再次汇集不同层次的特征图并将最终的分割结果输出。
通过以上优化措施PaddleSeg的肖像分割模型在保证分割精度的情况下大幅减少了参数量提高了模型的轻量化程度并且通过全局上下文信息的汇集和特征融合进一步提升了模型的语义理解能力和分割效果。
针对肖像分割任务数据量不足是影响分割精度的一个重要因素。为了解决这一问题PaddleSeg开源了PP-HumanSeg-14K数据集其中包含14000张室内场景半身人像的图片从一定程度上缓解了数据不足的问题。为了进一步提高模型的分割精度和泛化能力采用了迁移学习的方法。具体来说首先在大规模的通用人像分割数据集上进行预训练然后再针对PP-HumanSeg-14K数据集进行微调。
在调整模型的深度和宽度以平衡分割精度和推理速度方面模型的输入尺寸也是一个需要重视的变量。针对手机和电脑端常见的拍摄尺寸为1028x720的情况PP-HumanSeg v1肖像分割模型建议将图片缩放为398x224进行预测。为了进一步追求极致的推理速度PP-HumanSeg v2肖像分割模型将最佳输入尺寸进一步缩小为256x144从而将推理速度提升了52%相比输入尺寸398x224。虽然较小的输入尺寸会减少输入信息量但由于PP-HumanSeg v2模型具有更强的学习能力最终也能获得不错的分割效果。
综合考虑上述改进与PP-HumanSeg v1相比PP-HumanSeg v2肖像分割模型在推理速度手机端提升了45.5%mIoU精度提升了3.03%同时具有更佳的可视化效果。此外该模型还支持手机拍摄的横屏和竖屏输入图像针对室内场景可以开箱即用为用户提供了更加便捷和高效的人像分割解决方案。
通用人像分割模型
针对通用人像分割任务我们在PaddleSeg平台上使用了领先的模型在大规模数据集上进行了训练并发布了两个型号的PP-HumanSeg v2通用人像分割模型。
首先是PP-HumanSeg v2-Lite通用人像分割模型它采用了类似于肖像分割模型的结构并且特别适合在手机端的ARM CPU上进行部署。相比PP-HumanSeg v1-Lite模型PP-HumanSeg v2-Lite在精度上提升了6.5%的mIoU。这个模型可以有效地应用于移动端的人像分割场景提供更高质量的分割效果。
其次是PP-HumanSeg v2-Mobile通用人像分割模型它采用了PaddleSeg自研的PP-LiteSeg模型结构更适合在服务器端的GPU上进行部署。相比PP-HumanSeg v1-Mobile模型PP-HumanSeg v2-Mobile在精度上提升了1.49%的mIoU同时推理速度也提升了5.7%。这个模型适用于对分割精度和推理速度都有要求的场景为用户提供了更高效和准确的人像分割解决方案。
由于通用人像分割任务的场景变化很大我们建议用户在实际应用中评估PP-HumanSeg通用人像分割模型的精度。如果模型符合业务要求用户可以直接使用。如果需要进一步优化用户也可以基于PP-HumanSeg通用人像分割模型进行定制化优化以获得更好的效果。
模型部署
PP-HumanSeg 分割模型提供了最终模型和二次训练以其部署的功能代码。使用提供的肖像分割和通用人像分割配置文件用户只需准备好数据即可开始训练。该模型支持在多种硬件上进行应用部署包括NVIDIA GPU、X86 CPU、ARM CPU以及浏览器Web。
另外还对模型预测结果进行了形态学后处理操作以过滤掉背景干扰保留人像主体。具体流程如下图所示原始预测图像中每个像素的数值表示其为前景的概率。首先使用阈值操作来过滤掉概率较小的像素然后通过腐蚀和膨胀操作来消除细小的噪点。腐蚀操作的核尺寸小于膨胀操作然后将掩码图像应用于原始预测结果上得到最终的预测结果。通过形态学后处理可以有效地提升人像分割的可视化效果从而使分割结果更加清晰和准确。 C onnxruntime推理:
#define _CRT_SECURE_NO_WARNINGS
#include iostream
#include fstream
#include string
#include opencv2/imgproc.hpp
#include opencv2/highgui.hpp
//#include cuda_provider_factory.h ///使用cuda加速
#include onnxruntime_cxx_api.hclass pphuman_seg
{
public:pphuman_seg(std::string model_path);void inference(cv::Mat cv_src, std::vectorcv::Mat cv_dsts);
private:void preprocess(cv::Mat cv_src);int inpWidth;int inpHeight;std::vectorfloat input_image_;const float conf_threshold 0.5;Ort::Env env Ort::Env(ORT_LOGGING_LEVEL_ERROR, pphuman);Ort::Session *ort_session nullptr;Ort::SessionOptions sessionOptions Ort::SessionOptions();std::vectorchar* input_names;std::vectorchar* output_names;std::vectorstd::vectorint64_t input_node_dims; // 1 outputsstd::vectorstd::vectorint64_t output_node_dims; // 1 outputs
};pphuman_seg::pphuman_seg(std::string model_path)
{std::wstring widestr std::wstring(model_path.begin(), model_path.end()); //windows写法//OrtStatus* status OrtSessionOptionsAppendExecutionProvider_CUDA(sessionOptions, 0); //使用cuda加速sessionOptions.SetGraphOptimizationLevel(ORT_ENABLE_BASIC);ort_session new Ort::Session(env, widestr.c_str(), sessionOptions); //windows写法//ort_session new Session(env, model_path.c_str(), sessionOptions); //linux写法size_t numInputNodes ort_session-GetInputCount();size_t numOutputNodes ort_session-GetOutputCount();Ort::AllocatorWithDefaultOptions allocator;for (int i 0; i numInputNodes; i){input_names.push_back(ort_session-GetInputName(i, allocator));Ort::TypeInfo input_type_info ort_session-GetInputTypeInfo(i);auto input_tensor_info input_type_info.GetTensorTypeAndShapeInfo();auto input_dims input_tensor_info.GetShape();input_node_dims.push_back(input_dims);}for (int i 0; i numOutputNodes; i){output_names.push_back(ort_session-GetOutputName(i, allocator));Ort::TypeInfo output_type_info ort_session-GetOutputTypeInfo(i);auto output_tensor_info output_type_info.GetTensorTypeAndShapeInfo();auto output_dims output_tensor_info.GetShape();output_node_dims.push_back(output_dims);}this-inpHeight input_node_dims[0][2];this-inpWidth input_node_dims[0][3];
}void pphuman_seg::preprocess(cv::Mat cv_src)
{cv::Mat dstimg;resize(cv_src, dstimg, cv::Size(this-inpWidth, this-inpHeight), cv::INTER_LINEAR);int row dstimg.rows;int col dstimg.cols;this-input_image_.resize(row * col * dstimg.channels());for (int c 0; c 3; c){for (int i 0; i row; i){for (int j 0; j col; j){float pix dstimg.ptruchar(i)[j * 3 c];this-input_image_[c * row * col i * col j] (pix / 255.0 - 0.5) / 0.5;}}}
}void pphuman_seg::inference(cv::Mat cv_src,std::vectorcv::Mat cv_dsts)
{this-preprocess(cv_src);std::arrayint64_t, 4 input_shape_{1, 3, this-inpHeight, this-inpWidth};auto allocator_info Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);Ort::Value input_tensor_ Ort::Value::CreateTensorfloat(allocator_info, input_image_.data(),input_image_.size(), input_shape_.data(), input_shape_.size());std::vectorOrt::Value ort_outputs ort_session-Run(Ort::RunOptions{ nullptr }, input_names.data(),input_tensor_, 1, output_names.data(), output_names.size()); // 开始推理// post process. Ort::Value mask_pred ort_outputs.at(0);const int out_h this-output_node_dims[0][1];const int out_w this-output_node_dims[0][2];float *mask_ptr mask_pred.GetTensorMutableDatafloat();cv::Mat segmentation_map;cv::Mat mask_out(out_h, out_w, CV_32FC2, mask_ptr);cv::resize(mask_out, segmentation_map, cv::Size(cv_src.cols, cv_src.rows));cv::Mat cv_dst cv_src.clone();for (int h 0; h cv_src.rows; h){for (int w 0; w cv_src.cols; w){float pix segmentation_map.ptrfloat(h)[w * 2 1];if (pix this-conf_threshold){float b (float)cv_dst.atcv::Vec3b(h, w)[0];cv_dst.atcv::Vec3b(h, w)[0] uchar(b * 0.5 1);float g (float)cv_dst.atcv::Vec3b(h, w)[1] 255.0;cv_dst.atcv::Vec3b(h, w)[1] uchar(g * 0.5 1);float r (float)cv_dst.atcv::Vec3b(h, w)[2];cv_dst.atcv::Vec3b(h, w)[2] uchar(r * 0.5 1);}}}cv_dsts.push_back(cv_dst);cv::Mat cv_matting cv_src.clone();for (int h 0; h cv_src.rows; h){for (int w 0; w cv_src.cols; w){float pix segmentation_map.ptrfloat(h)[w * 2 1];if (pix this-conf_threshold){cv_matting.atcv::Vec3b(h, w)[0] (float)cv_src.atcv::Vec3b(h, w)[0];cv_matting.atcv::Vec3b(h, w)[1] (float)cv_src.atcv::Vec3b(h, w)[1];cv_matting.atcv::Vec3b(h, w)[2] (float)cv_src.atcv::Vec3b(h, w)[2];}else{cv_matting.atcv::Vec3b(h, w)[0] 255;cv_matting.atcv::Vec3b(h, w)[1] 255;cv_matting.atcv::Vec3b(h, w)[2] 255;}}}cv_dsts.push_back(cv_matting);
}void show_img(std::string name, const cv::Mat img)
{cv::namedWindow(name, 0);int max_rows 500;int max_cols 600;if (img.rows img.cols img.rows max_rows) {cv::resizeWindow(name, cv::Size(img.cols * max_rows / img.rows, max_rows));}else if (img.cols img.rows img.cols max_cols) {cv::resizeWindow(name, cv::Size(max_cols, img.rows * max_cols / img.cols));}cv::imshow(name, img);
}cv::Mat replaceBG(const cv::Mat cv_src, cv::Mat alpha, std::vectorint bg_color)
{int width cv_src.cols;int height cv_src.rows;cv::Mat cv_matting cv::Mat::zeros(cv::Size(width, height), CV_8UC3);float* alpha_data (float*)alpha.data;for (int i 0; i height; i){for (int j 0; j width; j){float alpha_ alpha_data[i * width j];cv_matting.at cv::Vec3b(i, j)[0] cv_src.at cv::Vec3b(i, j)[0] * alpha_ (1 - alpha_) * bg_color[0];cv_matting.at cv::Vec3b(i, j)[1] cv_src.at cv::Vec3b(i, j)[1] * alpha_ (1 - alpha_) * bg_color[1];cv_matting.at cv::Vec3b(i, j)[2] cv_src.at cv::Vec3b(i, j)[2] * alpha_ (1 - alpha_) * bg_color[2];}}return cv_matting;
}int main()
{pphuman_seg pp_net(model_float32.onnx);std::string path images;std::vectorstd::string filenames;cv::glob(path, filenames, false);for (auto file_name : filenames){cv::Mat cv_src cv::imread(file_name);std::vectorcv::Mat cv_dsts;pp_net.inference(cv_src,cv_dsts);show_img(src, cv_src);show_img(matting, cv_dsts[0]);show_img(dst, cv_dsts[1]);cv::waitKey(0);}
}python onnxruntimer推理
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import copy
import argparse
import cv2
import numpy as np
import onnxruntimeclass pphumanseg:def __init__(self, conf_thres0.5):self.conf_threshold conf_thres# Initialize modelself.onnx_session onnxruntime.InferenceSession(model_float32.onnx)self.input_name self.onnx_session.get_inputs()[0].nameself.output_name self.onnx_session.get_outputs()[0].nameself.input_shape self.onnx_session.get_inputs()[0].shapeself.input_height self.input_shape[2]self.input_width self.input_shape[3]self.mean np.array([0.5, 0.5, 0.5], dtypenp.float32).reshape(1,1,3)self.std np.array([0.5, 0.5, 0.5], dtypenp.float32).reshape(1,1,3)def prepare_input(self, image):input_image cv2.resize(image, dsize(self.input_width, self.input_height))input_image (input_image.astype(np.float32) / 255.0 - self.mean) / self.stdinput_image input_image.transpose(2, 0, 1)input_image np.expand_dims(input_image, axis0)return input_imagedef detect(self, image):input_image self.prepare_input(image)# Perform inference on the imageresult self.onnx_session.run([self.output_name], {self.input_name: input_image})# Post process:squeezesegmentation_map result[0]segmentation_map np.squeeze(segmentation_map)image_width, image_height image.shape[1], image.shape[0]dst_image copy.deepcopy(image)segmentation_map cv2.resize(segmentation_map,dsize(image_width, image_height),interpolationcv2.INTER_LINEAR,)# color listcolor_image_list []# ID 0:BackGroundbg_image np.zeros(image.shape, dtypenp.uint8)bg_image[:] (0, 0, 0)color_image_list.append(bg_image)# ID 1:Humanbg_image np.zeros(image.shape, dtypenp.uint8)bg_image[:] (0, 255, 0)color_image_list.append(bg_image)# Overlay segmentation mapmasks segmentation_map.transpose(2, 0, 1)for index, mask in enumerate(masks):# Threshold check by scoremask np.where(mask self.conf_threshold, 0, 1)# Overlaymask np.stack((mask,) * 3, axis-1).astype(uint8)mask_image np.where(mask, dst_image, color_image_list[index])dst_image cv2.addWeighted(dst_image, 0.5, mask_image, 0.5, 1.0)return dst_imageif __name__ __main__:parser argparse.ArgumentParser()parser.add_argument(--imgpath, typestr, defaultimages/person.jpg, helpimage path)parser.add_argument(--confThreshold, default0.5, typefloat, helpclass confidence)parser.add_argument(--use_video, typeint, default1, helpif use video)args parser.parse_args()segmentor pphumanseg(conf_thresargs.confThreshold)if args.use_video ! 1:srcimg cv2.imread(args.imgpath)# Detect Objectsdstimg segmentor.detect(srcimg)winName pphumanseg in ONNXRuntimecv2.namedWindow(winName, 0)cv2.imshow(winName, dstimg)cv2.waitKey(0)cv2.destroyAllWindows()else:cap cv2.VideoCapture(0) while True:ret, frame cap.read()if not ret:breakdstimg segmentor.detect(frame)key cv2.waitKey(1)if key 27: # ESCbreakcv2.imshow(pphumanseg Demo, dstimg)cap.release()cv2.destroyAllWindows() 文章转载自: http://www.morning.fnywn.cn.gov.cn.fnywn.cn http://www.morning.jppdk.cn.gov.cn.jppdk.cn http://www.morning.rcjwl.cn.gov.cn.rcjwl.cn http://www.morning.bloao.com.gov.cn.bloao.com http://www.morning.zrkp.cn.gov.cn.zrkp.cn http://www.morning.zymgs.cn.gov.cn.zymgs.cn http://www.morning.nbdtdjk.cn.gov.cn.nbdtdjk.cn http://www.morning.xzrbd.cn.gov.cn.xzrbd.cn http://www.morning.thbkc.cn.gov.cn.thbkc.cn http://www.morning.sloxdub.cn.gov.cn.sloxdub.cn http://www.morning.caswellintl.com.gov.cn.caswellintl.com http://www.morning.zxdhp.cn.gov.cn.zxdhp.cn http://www.morning.bnfjh.cn.gov.cn.bnfjh.cn http://www.morning.tkrdg.cn.gov.cn.tkrdg.cn http://www.morning.litao4.cn.gov.cn.litao4.cn http://www.morning.mtrrf.cn.gov.cn.mtrrf.cn http://www.morning.qtsks.cn.gov.cn.qtsks.cn http://www.morning.mqxzh.cn.gov.cn.mqxzh.cn http://www.morning.ylpwc.cn.gov.cn.ylpwc.cn http://www.morning.rnrfs.cn.gov.cn.rnrfs.cn http://www.morning.pwzzk.cn.gov.cn.pwzzk.cn http://www.morning.hhpkb.cn.gov.cn.hhpkb.cn http://www.morning.bpttm.cn.gov.cn.bpttm.cn http://www.morning.ffcsr.cn.gov.cn.ffcsr.cn http://www.morning.dnzyx.cn.gov.cn.dnzyx.cn http://www.morning.crrjg.cn.gov.cn.crrjg.cn http://www.morning.ddxjr.cn.gov.cn.ddxjr.cn http://www.morning.mhmcr.cn.gov.cn.mhmcr.cn http://www.morning.nrfrd.cn.gov.cn.nrfrd.cn http://www.morning.tqpds.cn.gov.cn.tqpds.cn http://www.morning.gfjgq.cn.gov.cn.gfjgq.cn http://www.morning.glwyn.cn.gov.cn.glwyn.cn http://www.morning.hlnrj.cn.gov.cn.hlnrj.cn http://www.morning.pqnpd.cn.gov.cn.pqnpd.cn http://www.morning.ey3h2d.cn.gov.cn.ey3h2d.cn http://www.morning.bkpbm.cn.gov.cn.bkpbm.cn http://www.morning.pszw.cn.gov.cn.pszw.cn http://www.morning.hlkxb.cn.gov.cn.hlkxb.cn http://www.morning.zdbfl.cn.gov.cn.zdbfl.cn http://www.morning.lcbnb.cn.gov.cn.lcbnb.cn http://www.morning.xfwnk.cn.gov.cn.xfwnk.cn http://www.morning.njddz.cn.gov.cn.njddz.cn http://www.morning.ntyks.cn.gov.cn.ntyks.cn http://www.morning.cpqqf.cn.gov.cn.cpqqf.cn http://www.morning.ypqwm.cn.gov.cn.ypqwm.cn http://www.morning.tsnwf.cn.gov.cn.tsnwf.cn http://www.morning.qsy40.cn.gov.cn.qsy40.cn http://www.morning.jljiangyan.com.gov.cn.jljiangyan.com http://www.morning.hrtwt.cn.gov.cn.hrtwt.cn http://www.morning.tnkwj.cn.gov.cn.tnkwj.cn http://www.morning.c7495.cn.gov.cn.c7495.cn http://www.morning.bbrf.cn.gov.cn.bbrf.cn http://www.morning.lpnpn.cn.gov.cn.lpnpn.cn http://www.morning.yqmmh.cn.gov.cn.yqmmh.cn http://www.morning.pqktp.cn.gov.cn.pqktp.cn http://www.morning.cpmwg.cn.gov.cn.cpmwg.cn http://www.morning.rycbz.cn.gov.cn.rycbz.cn http://www.morning.pljdy.cn.gov.cn.pljdy.cn http://www.morning.rkyw.cn.gov.cn.rkyw.cn http://www.morning.wmmtl.cn.gov.cn.wmmtl.cn http://www.morning.xgchm.cn.gov.cn.xgchm.cn http://www.morning.httpm.cn.gov.cn.httpm.cn http://www.morning.qbjrf.cn.gov.cn.qbjrf.cn http://www.morning.xrpjr.cn.gov.cn.xrpjr.cn http://www.morning.nxzsd.cn.gov.cn.nxzsd.cn http://www.morning.ktmnq.cn.gov.cn.ktmnq.cn http://www.morning.xlztn.cn.gov.cn.xlztn.cn http://www.morning.dfwkn.cn.gov.cn.dfwkn.cn http://www.morning.kdnrc.cn.gov.cn.kdnrc.cn http://www.morning.bprsd.cn.gov.cn.bprsd.cn http://www.morning.nqrfd.cn.gov.cn.nqrfd.cn http://www.morning.mjglk.cn.gov.cn.mjglk.cn http://www.morning.rtqyy.cn.gov.cn.rtqyy.cn http://www.morning.phjny.cn.gov.cn.phjny.cn http://www.morning.mrcpy.cn.gov.cn.mrcpy.cn http://www.morning.knpbr.cn.gov.cn.knpbr.cn http://www.morning.wfzdh.cn.gov.cn.wfzdh.cn http://www.morning.qyhcm.cn.gov.cn.qyhcm.cn http://www.morning.drytb.cn.gov.cn.drytb.cn http://www.morning.jggr.cn.gov.cn.jggr.cn