opencv学习笔记五十九:图像融合之背景替换

40 篇文章 4 订阅

以证件照为例,图片中有大部分为背景,先用kmeans对图像进行分割,可以得到背景的标签,然后将图像分为前景和背景两部分,非背景的都当作前景,显示kmeans分割后的图像dst,将原图像前景赋给dst, 背景都设为0,得到kmeans分割后的图像如下,可看到边缘处有一些小蓝边,过渡比较粗超:

 所以设置遮罩层对边缘进行融合,新建掩码mask单通道图像,将前景部分置1,背景部分置0,然后对mask进行腐蚀和高斯模糊,则mask前景部分为1,背景部分为0,边缘部分非0和1。新建结果图像result,对于mask中前景部分,将原图像赋给result,对于mask中背景部分,将随机生成的颜色赋给result,对于边缘部分,对前景和背景进行融合。

可看到边缘融合后的图像看起来就比较和谐了。

 
  1. #include<opencv2\opencv.hpp>

  2. using namespace cv;

  3.  
  4. int main(int arc, char** argv) {

  5. Mat src = imread("1.jpg");

  6. namedWindow("input", CV_WINDOW_AUTOSIZE);

  7. imshow("input", src);

  8.  
  9. //组装数据并运行KMeans

  10. int width = src.cols;

  11. int height = src.rows;

  12. int dims = src.channels();

  13. int pointsCount = width * height;

  14. Mat points(pointsCount, dims, CV_32F);//kmeans要求的数据为float类型的

  15. int index = 0;

  16. for (int i = 0; i < height; i++) {

  17. for (int j = 0; j < width; j++) {

  18. index = i*width + j;

  19. points.at<float>(index, 0) = src.at<Vec3b>(i, j)[0];

  20. points.at<float>(index, 1) = src.at<Vec3b>(i, j)[1];

  21. points.at<float>(index, 2) = src.at<Vec3b>(i, j)[2];

  22. }

  23. }

  24. Mat bestLabels;

  25. Mat centers;

  26. kmeans(points, 4, bestLabels, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 10, 0.1),3,2,centers);

  27.  
  28. //去背景+遮罩层

  29. Mat mask(src.size(), CV_8UC1);

  30. index = src.cols * 2 + 2;

  31. int bindex = bestLabels.at<int>(index, 0);//获得kmeans后背景的标签

  32.  
  33. Mat dst;

  34. src.copyTo(dst);

  35. for (int i = 0; i < height; i++) {

  36. for (int j = 0; j < width; j++) {

  37. index = i*width + j;

  38. int label = bestLabels.at<int>(index, 0);

  39. if (label == bindex) {

  40. dst.at<Vec3b>(i, j)[0] = 0;

  41. dst.at<Vec3b>(i, j)[1] = 0;

  42. dst.at<Vec3b>(i, j)[2] = 0;

  43. mask.at<uchar>(i, j) = 0;

  44. }

  45. else {

  46. mask.at<uchar>(i, j) = 255;

  47. }

  48. }

  49. }

  50. imshow("mask", mask);

  51. imshow("kmeans", dst);

  52.  
  53. //对掩码进行腐蚀+高斯模糊

  54. Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));

  55. erode(mask, mask, kernel);

  56. imshow("erode mask", mask);

  57. GaussianBlur(mask, mask, Size(3, 3), 0, 0);

  58. imshow("blur mask", mask);

  59.  
  60. //通道混合

  61. Vec3b color;

  62. color[0] = theRNG().uniform(0, 255);

  63. color[1] = theRNG().uniform(0, 255);

  64. color[2] = theRNG().uniform(0, 255);

  65.  
  66. Mat result(src.size(), src.type());

  67. double w = 0.0;

  68. int b = 0, g = 0, r = 0;

  69. int b1 = 0, g1 = 0, r1 = 0;

  70. int b2 = 0, g2 = 0, r2 = 0;

  71.  
  72. for (int i = 0; i < height; i++) {

  73. for (int j = 0; j < width; j++) {

  74. int m = mask.at<uchar>(i, j);

  75. if (m == 255) {

  76. result.at<Vec3b>(i, j) = src.at<Vec3b>(i, j);//将原图像中前景赋给结果图像中的前景

  77. }

  78. else if (m == 0) {

  79. result.at<Vec3b>(i, j) = color;//将随机生成的颜色赋给结果图像中的背景

  80. }

  81. else {

  82. w = m / 255.0;//权重

  83. //边缘前景

  84. b1 = src.at<Vec3b>(i, j)[0];

  85. g1= src.at<Vec3b>(i, j)[1];

  86. r1 = src.at<Vec3b>(i, j)[2];

  87. //边缘背景

  88. b2 = color[0];

  89. g2 = color[1];

  90. r2 = color[2];

  91. //边缘融合

  92. b = b1*w + b2 *(1.0 - w);

  93. g = g1*w + g2 *(1.0 - w);

  94. r = r1*w + r2 *(1.0 - w);

  95. result.at<Vec3b>(i, j)[0] = b;

  96. result.at<Vec3b>(i, j)[1] = g;

  97. result.at<Vec3b>(i, j)[2] = r;

  98. }

  99. }

  100. }

  101. imshow("result",result);

  102. waitKey(0);

  103. return 0;

  104. }

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值