opencv学习—图像融合之背景替换
Posted 机器人与智能系统研究院
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了opencv学习—图像融合之背景替换相关的知识,希望对你有一定的参考价值。
证件照大家都回经常用,但是在公司和学校有时需要蓝底免冠照,有的需要白底免冠照,有的还需要红底照,那我们是都准备好以备不时之需还是用的时候直接操作?急用直接换背景色无非就是PS来P图,但不是所有的人都会玩PS,而且技术不好,P出来的图也不能用,今天小编用opencv来教你怎么完美更换照片底色。
以证件照为例,图片中有大部分为背景,先用kmeans对图像进行分割,可以得到背景的标签,然后将图像分为前景和背景两部分,非背景的都当作前景,显示kmeans分割后的图像dst,将原图像前景赋给dst, 背景都设为0,得到kmeans分割后的图像如下,可看到边缘处有一些小蓝边,过渡比较粗超:
所以设置遮罩层对边缘进行融合,新建掩码mask单通道图像,将前景部分置1,背景部分置0,然后对mask进行腐蚀和高斯模糊,则mask前景部分为1,背景部分为0,边缘部分非0和1。新建结果图像result,对于mask中前景部分,将原图像赋给result,对于mask中背景部分,将随机生成的颜色赋给result,对于边缘部分,对前景和背景进行融合。
可看到边缘融合后的图像看起来就比较和谐了。
源代码:
#include<opencv2\opencv.hpp>
using namespace cv;
int main(int arc, char** argv) {
Mat src = imread("1.jpg");
namedWindow("input", CV_WINDOW_AUTOSIZE);
imshow("input", src);
//组装数据并运行KMeans
int width = src.cols;
int height = src.rows;
int dims = src.channels();
int pointsCount = width * height;
Mat points(pointsCount, dims, CV_32F);//kmeans要求的数据为float类型的
int index = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
index = i*width + j;
points.at<float>(index, 0) = src.at<Vec3b>(i, j)[0];
points.at<float>(index, 1) = src.at<Vec3b>(i, j)[1];
points.at<float>(index, 2) = src.at<Vec3b>(i, j)[2];
}
}
Mat bestLabels;
Mat centers;
kmeans(points, 4, bestLabels, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 10, 0.1),3,2,centers);
//去背景+遮罩层
Mat mask(src.size(), CV_8UC1);
index = src.cols * 2 + 2;
int bindex = bestLabels.at<int>(index, 0);//获得kmeans后背景的标签
Mat dst;
src.copyTo(dst);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
index = i*width + j;
int label = bestLabels.at<int>(index, 0);
if (label == bindex) {
dst.at<Vec3b>(i, j)[0] = 0;
dst.at<Vec3b>(i, j)[1] = 0;
dst.at<Vec3b>(i, j)[2] = 0;
mask.at<uchar>(i, j) = 0;
}
else {
mask.at<uchar>(i, j) = 255;
}
}
}
imshow("mask", mask);
imshow("kmeans", dst);
//对掩码进行腐蚀+高斯模糊
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
erode(mask, mask, kernel);
imshow("erode mask", mask);
GaussianBlur(mask, mask, Size(3, 3), 0, 0);
imshow("blur mask", mask);
//通道混合
Vec3b color;
color[0] = theRNG().uniform(0, 255);
color[1] = theRNG().uniform(0, 255);
color[2] = theRNG().uniform(0, 255);
Mat result(src.size(), src.type());
double w = 0.0;
int b = 0, g = 0, r = 0;
int b1 = 0, g1 = 0, r1 = 0;
int b2 = 0, g2 = 0, r2 = 0;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int m = mask.at<uchar>(i, j);
if (m == 255) {
result.at<Vec3b>(i, j) = src.at<Vec3b>(i, j);//将原图像中前景赋给结果图像中的前景
}
else if (m == 0) {
result.at<Vec3b>(i, j) = color;//将随机生成的颜色赋给结果图像中的背景
}
else {
w = m / 255.0;//权重
//边缘前景
b1 = src.at<Vec3b>(i, j)[0];
g1= src.at<Vec3b>(i, j)[1];
r1 = src.at<Vec3b>(i, j)[2];
//边缘背景
b2 = color[0];
g2 = color[1];
r2 = color[2];
//边缘融合
b = b1*w + b2 *(1.0 - w);
g = g1*w + g2 *(1.0 - w);
r = r1*w + r2 *(1.0 - w);
result.at<Vec3b>(i, j)[0] = b;
result.at<Vec3b>(i, j)[1] = g;
result.at<Vec3b>(i, j)[2] = r;
}
}
}
imshow("result",result);
waitKey(0);
return 0;
}
研究院交流群
机器人与智能系统研究院 微信交流学习群已经建立,有问题请@群中相关方向博士和工作大佬解答讨论,研究方向主要有计算机视觉之三维重构,图像处理,机器人视觉系统。长按二维码加管理员微信,管理员抱你入群,本群纯粹为了学习讨论,与广告宣传的朋友请绕行。
以上是关于opencv学习—图像融合之背景替换的主要内容,如果未能解决你的问题,请参考以下文章