【SRC-CPP-OpenCV】给图片更换背景色

文章目录

  • Part.I Introduction
  • Part.II Main_body
    • Chap.I 源码简析
    • Chap.II 效果展示
  • Part.III 源码
  • Reference

Part.I Introduction

本文将介绍如何用 OpenCV 更换图片的背景色(附有完整代码)。

Part.II Main_body

Chap.I 源码简析

配置部分:包括输入文件名、输出文件名、需要更换的背景色(可以尝试随机背景色)

	string filename_in = "A:/OHanlon/Desktop/1017451354889.png";string filename_out = "A:/OHanlon/Desktop/a.png";Vec3b color;    // 设置的背景色RNG rng(12345);color[0] = 255; // rng.uniform(0, 255);color[1] = 255; // rng.uniform(0, 255);color[2] = 255; // rng.uniform(0, 255);

数据处理部分的流程大致如下:

  1. 将二维图像数据线性化
  2. 使用 K-means 聚类;分离出背景色
  3. 背景与前景二值化
  4. 腐蚀 + 高斯模糊:图像与背景交汇处高斯模糊化
  5. 更换背景色以及交汇处融合处理

调用 OpenCV 里面的主要的函数

// k 均值聚类
kmeans(data, numCluster, labels, criteria, 3, KMEANS_PP_CENTERS);
// 高斯模糊
GaussianBlur(mask, mask, Size(3, 3), 0, 0);

Chap.II 效果展示

示例一:

在这里插入图片描述
存在如下几个问题:

  1. 图片中的文字和箭头也被当作背景给消掉了
  2. 非背景和背景的边缘有些模糊,可能做了模糊处理,有可能原图的分辨率就很低

示例二

在这里插入图片描述
这个还不错

Part.III 源码

整个源码如下:

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui_c.h>using namespace std;
using namespace cv;bool _changeBackgroundColor()
{
#pragma region BASIC Configurationstring filename_in = "A:/OHanlon/Desktop/1017451354889.png";string filename_out = "A:/OHanlon/Desktop/a.png";Vec3b color;    // 设置的背景色RNG rng(12345);color[0] = 255; // b rng.uniform(0, 255);color[1] = 255; // g rng.uniform(0, 255);color[2] = 255; // r rng.uniform(0, 255);
#pragma endregion#pragma region ProcessingMat src = imread(filename_in);if (src.empty()) {printf("could not load image...\n");return false;}namedWindow("原图", 0);cvResizeWindow("原图", 500, 500);imshow("原图", src);// 1.将二维图像数据线性化Mat data;for (int i = 0; i < src.rows; i++)     //像素点线性排列for (int j = 0; j < src.cols; j++){Vec3b point = src.at<Vec3b>(i, j);Mat tmp = (Mat_<float>(1, 3) << point[0], point[1], point[2]);data.push_back(tmp);}// 2.使用K-means聚类;分离出背景色int numCluster = 4;Mat labels;TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 10, 0.1);kmeans(data, numCluster, labels, criteria, 3, KMEANS_PP_CENTERS);// 3.背景与人物二值化Mat mask = Mat::zeros(src.size(), CV_8UC1);int index = src.rows * 2 + 2;  //获取点(2,2)作为背景色int cindex = labels.at<int>(index);/*  提取背景特征 */for (int row = 0; row < src.rows; row++){for (int col = 0; col < src.cols; col++){index = row * src.cols + col;int label = labels.at<int>(index);if (label == cindex) { // 背景mask.at<uchar>(row, col) = 0;}else {mask.at<uchar>(row, col) = 255;}}}//imshow("mask", mask);// 4.腐蚀 + 高斯模糊:图像与背景交汇处高斯模糊化Mat k = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));erode(mask, mask, k);//imshow("erode-mask", mask);GaussianBlur(mask, mask, Size(3, 3), 0, 0);//imshow("Blur Mask", mask);// 5.更换背景色以及交汇处融合处理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 row = 0; row < src.rows; row++){for (int col = 0; col < src.cols; col++){int m = mask.at<uchar>(row, col);if (m == 255) {result.at<Vec3b>(row, col) = src.at<Vec3b>(row, col); // 前景}else if (m == 0) {result.at<Vec3b>(row, col) = color; // 背景}else {/* 融合处理部分 */w = m / 255.0;b1 = src.at<Vec3b>(row, col)[0];g1 = src.at<Vec3b>(row, col)[1];r1 = src.at<Vec3b>(row, col)[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>(row, col)[0] = b;result.at<Vec3b>(row, col)[1] = g;result.at<Vec3b>(row, col)[2] = r;}}}
#pragma endregionnamedWindow("背景替换", 0);cvResizeWindow("背景替换", 500, 500);imshow("背景替换", result);imwrite(filename_out, result);waitKey(0);return true;
}

Reference

  • OpenCV案例(五): 更换背景色

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/685695.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

02.文件IO

文件描述符 表述打开的文件的 它是open函数的返回值&#xff0c;一个进程启动之后&#xff0c;会默认打开3个文件标识符 0标准输入&#xff0c;1标准输出&#xff0c;2标准错误 新的打开的文件返回文件描述符表中未使用过的最小的文件描述符 open函数 用来打开或者新建一个文件…

九.吊打面试官系列-Tomcat优化-深入源码剖析Tomcat启动流程

前言 上篇文章《Tomcat优化-Tomcat如何打破双亲委派》我们深入分析了一下JVM的ClassLoader类加载器机制&#xff0c;以及Tomcat通过打破双亲委派来实现自己的加载隔离&#xff0c;本篇文章接着上篇文章分析Tomcat的启动流程&#xff0c;主要是看Tomcat是如何进行初始化的。如果…

burp靶场xss漏洞(初级篇)

靶场地址 http://portswigger.net/web-security/all-labs#cross-site-scripting 第一关&#xff1a;反射型 1.发现搜索框直接注入payload <script>alert(111)</script> ​ 2.出现弹窗即说明攻击成功 ​ 第二关&#xff1a;存储型 1.需要在评论里插入payload …

Keycloak实战+spring boot

标题 前言项目搭建前言 最近项目中使用keycloak,为了更好的上手,我先本地Windows搭建一套demo 项目搭建 我本地jdk版本号为: 通过网上查询一些资料查看,jdk1.8对应的keycloak版本为:15的版本,但是没有找到,我只能下载如下: 通过码云我找到了具体的版本号,开始下…

每周打靶VulnHub靶机-DEATHNOTE_ 1

Deathnote: 1 靶机传送门 don’t waste too much time thinking outside the box . It is a Straight forward box . 不要浪费太多时间跳出框框思考问题。这是一个很直接的盒子 是不是所有线索都在这个盒子里&#xff1f; 1.信息搜集 使用nmap进行域内存活主机扫描发现target …

Maven的使用

1.第一个Maven工程 1.1 创建约定目录结构 ​ Hello ​ src ​ ——main(存放主程序) ​ ————java(存放源代码文件) ​ ————resources(存放配置文件和资源文件) ​ ——test(存放测试程序) ​ ————java ​ ————resources ​ pom.xml 1.2 创建核心文件 pom.xml …

帆软报表实现填报报表

我们拿emp表举例 登记信息表 设计一个报表实现对emp表员工的登记 &#xff08;emp表为ORACLE自带用户scott下的一个表&#xff09; 首先&#xff0c;我们设计好填报界面&#xff0c;新建一个普通报表&#xff0c;将emp表中需要的输入一一回应填写进表中。 如下图所示&#xf…

CAPL如何实现TLS握手认证

CAPL有专门的章节介绍如何实现TLS握手认证的函数: CAPL调用哪些函数实现TLS握手认证,需要了解TLS在整个通信过程的哪个阶段。 首先TCP需要建立连接,这是TLS握手的前提。当TLS握手认证完成后,可以传输数据。 所以TLS握手开始前需要确保TCP建立连接,TCP传输数据前需要确保…

HFSS学习-day4-建模操作

通过昨天的学习&#xff0c;我们已经熟悉了HFSS的工作环境&#xff1b;今天我们来讲解HFSS中创建物体模型的县体步骤和相关操作。物体建模是HFSS仿真设计工作的第一步&#xff0c;HFSS中提供了诸如矩形、圆面、长方体圆柱体和球体等多种基本模型(Primitive)&#xff0c;这些基本…

【唇形同步】Diff2Lip: Audio Conditioned Diffusion Models for Lip-Synchronization

摘要 嘴唇同步的任务&#xff08;唇同步&#xff09;寻求将人脸的嘴唇与不同的音频相匹配。它在电影行业以及创建虚拟化身和视频会议中有各种应用。这是一个具有挑战性的问题&#xff0c;因为人们需要同时引入详细、逼真的嘴唇动作&#xff0c;同时保持身份、姿势、情绪和图像…

【每日刷题】Day36

【每日刷题】Day36 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 232. 用栈实现队列 - 力扣&#xff08;LeetCode&#xff09; 2. 2960. 统计已测试设备 - 力扣&#…

数据库调优-SQL语句优化

2. SQL语句优化 sql 复制代码 # 请问这两条SQL语句有什么区别呢&#xff1f;你来猜一猜那条SQL语句执行查询效果更好&#xff01; select id from sys_goods where goods_name华为 HUAWEI 麦芒7 魅海蓝 6G64G 全网通; ​ select id from sys_goods where goods_id14967325985…