1.实现代码
void LFMatting(const cv::Mat& cv_src,cv::Mat &cv_matting, cv::Mat& cv_dst, cv::dnn::Net& net, int target_w = 640, int target_h = 960);
void imshow(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);
}
void mergeImage(std::vector<cv::Mat>& src_vor, cv::Mat& cv_dst, int channel)
{
cv::Mat img_merge;
cv::Size size(src_vor.at(0).cols * src_vor.size(), src_vor.at(0).rows);
if (channel == 1)
{
img_merge.create(size, CV_8UC1);
}
else if (channel == 3)
{
img_merge.create(size, CV_8UC3);
}
for (int i = 0; i < src_vor.size(); i++)
{
cv::Mat cv_temp = img_merge(cv::Rect(src_vor.at(i).cols * i, 0, src_vor.at(i).cols, src_vor.at(i).rows));
src_vor.at(i).copyTo(cv_temp);
}
cv_dst = img_merge.clone();
}
cv::Mat channelSwitching(const cv::Mat& cv_src)
{
cv::Mat three_channel = cv::Mat::zeros(cv_src.rows, cv_src.cols, CV_8UC3);
std::vector<cv::Mat> channels;
if (cv_src.channels() == 1)
{
for (int i = 0; i < 3; i++)
{
channels.push_back(cv_src);
}
merge(&channels[0], channels.size(), three_channel);
}
return three_channel;
}
int main(int argc, char* argv[])
{
cv::dnn::Net net = cv::dnn::readNet("model/graph_final_960_640.pb", "model/graph_final_960_640.pbtxt");
std::string path = "images";
std::vector<std::string> filenames;
cv::glob(path, filenames, false);
for (auto v : filenames)
{
cv::Mat cv_src = cv::imread(v,1);
std::vector<cv::Mat> cv_dsts(3);
cv::Mat cv_matting, cv_dst;
cv_dsts[0] = cv_src.clone();
LFMatting(cv_src,cv_matting, cv_dsts[2], net);
cv_dsts[1] = channelSwitching(cv_matting);
cv_dsts[1].convertTo(cv_dsts[1], CV_8UC3, 255);
mergeImage(cv_dsts, cv_dst, 3);
cv::imwrite("dst.jpg", cv_dst);
//cv::waitKey();
}
return 0;
}
void LFMatting(const cv::Mat& cv_src,cv::Mat &cv_matting, cv::Mat& cv_dst, cv::dnn::Net& net, int target_w,int target_h)
{
cv::Size reso(target_h, target_w);
cv::Mat blob = cv::dnn::blobFromImage(cv_src, 1.0, reso,
cv::Scalar(127.156207, 115.917443, 106.031127), true, false);
net.setInput(blob);
std::vector<cv::Mat> outputs;
std::vector<std::string> names = {
"deFG_side_0_out/ResizeNearestNeighbor",
"deBG_side_0_out/ResizeNearestNeighbor",
"fusion_sigmoid_output/Sigmoid"
};
net.forward(outputs, names);
auto t1 = cv::getTickCount();
for (size_t i = 0; i < outputs.size(); ++i)
{
outputs[i] = outputs[i].reshape(0, { outputs[i].size[2], outputs[i].size[3] });
cv::resize(outputs[i], outputs[i], cv_src.size(), 0.0, 0.0, cv::INTER_LINEAR);
}
cv::Mat fg = outputs[0];
cv::Mat bg = outputs[1];
cv::Mat alpha = outputs[2];
cv_matting = fg.mul(alpha) + (1.0 - bg).mul(1.0 - alpha);
cv_dst = cv::Mat::zeros(cv::Size(cv_src.cols, cv_src.rows), CV_8UC3);
const int bg_color[3] = { 219,142,67 };
float* alpha_data = (float*)alpha.data;
for (int i = 0; i < cv_matting.rows; i++)
{
for (int j = 0; j < cv_matting.cols; j++)
{
float alpha_ = alpha_data[i * cv_matting.cols + j];
cv_dst.at < cv::Vec3b>(i, j)[0] = cv_src.at < cv::Vec3b>(i, j)[0] * alpha_ + (1 - alpha_) * bg_color[0];
cv_dst.at < cv::Vec3b>(i, j)[1] = cv_src.at < cv::Vec3b>(i, j)[1] * alpha_ + (1 - alpha_) * bg_color[1];
cv_dst.at < cv::Vec3b>(i, j)[2] = cv_src.at < cv::Vec3b>(i, j)[2] * alpha_ + (1 - alpha_) * bg_color[2];
}
}
}
2.一些不错的效果:
3.还有一些是场景处理不是很好。
4. 我现在训练的样本在10000张左右,如果加大样本量或者优化下算法,是可以解决掉这些问题点。
5. 模型和源码都上传到CSDN,感兴趣的可以下载试玩:https://download.csdn.net/download/matt45m/51419768