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

news2024/11/18 15:30:17

文章目录

  • 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 Configuration
    string 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 Processing
    Mat 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 endregion
    namedWindow("背景替换", 0);
    cvResizeWindow("背景替换", 500, 500);
    imshow("背景替换", result);
    imwrite(filename_out, result);
    waitKey(0);
    return true;
}

Reference

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Electron 报错:WinState is not a constructor

文章目录 问题分析 问题 在使用 electron-win-state 库时报错如下 代码如下&#xff1a; const WinState require(electron-win-state) const winState new WinState({ defaultWidth: 800,defaultHeight: 600,// other winState options, see below })const browserWindow…

区块链的跨链交互:从学校间交流看跨链技术

区块链是一种去中心化的分布式账本技术&#xff0c;它通过加密学和共识机制来确保数据的安全性和不可篡改性。每个区块链就像一所独立的学校&#xff0c;有自己的制度、学生和重点专业。它们各自运行&#xff0c;有时在同一领域展开不同的活动。随着区块链技术的不断发展&#…

Java入门基础学习笔记15——强制类型转换

大范围类型的变量是否可以赋值给小范围类型的变量呢&#xff1f; IDEA直接报错。直接报错&#xff0c;是提醒你有问题。但是我非常进行类型转换。 非要强行赋值呢&#xff1f; 强制类型转换&#xff0c;强行将类型范围大的变量&#xff0c;数据赋值给类型范围小的变量。 数据…

几个字符串函数的使用和模拟实现(1)

下面介绍几个常见的字符串函数的使用并且学会自己创建实现与它们一样的功能&#xff0c;借此来巩固与字符串、函数、指针相关方面的知识。 strlen函数&#xff08;头文件是<string.h>&#xff09; 由此可见&#xff1a; strlen函数的返回值是返回值是size_t&#xff0c;…

【回溯 状态压缩 深度优先】37. 解数独

本文涉及知识点 回溯 状态压缩 深度优先 LeetCode37. 解数独 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只…

突然连接不上 Bitbucket.org?

提交或拉取时都出现了错误 查找一下 Bitbucket.org 的IP&#xff0c;使用这个网址 https://site.ip138.com/bitbucket.org/ 找到C:\Windows\System32\drivers\etc下的hosts文件用记事本/notepad 打开&#xff0c;咱加到host文件里面 一切又恢复正常

UE5 C++软引用

一.软引用通常是仅储存资源对象的资源路径没有与资源产生耦合关系的引用&#xff08;软引用加载到内存中&#xff0c;只有在需要的时候才会被加载&#xff09; 软引用通常有FSoftObjectPath、FSoftClassPath、TSoftObjectPtr、TSoftClassPtr。它指向的资源未被加载&#xff0c…

四足机器人摆线规划程序

一、标准摆线公式 { x r ∗ ( θ − sin ⁡ ( θ ) ) y r ∗ ( 1 − cos ⁡ ( θ ) ) \left\{\begin{array}{l} xr *(\theta-\sin (\theta)) \\ yr *(1-\cos (\theta)) \end{array}\right. {xr∗(θ−sin(θ))yr∗(1−cos(θ))​ 这里的r表示摆线的圆的半径&#xff0c; θ \…

codeforces round944(div4)A~E题解

文章目录 [A. My First Sorting Problem](https://codeforces.com/contest/1971/problem/A)[B. Different String](https://codeforces.com/contest/1971/problem/B)[C. Clock and Strings](https://codeforces.com/contest/1971/problem/C)[D. Binary Cut](https://codeforces…

性能测试 --概念

什么是性能测试 性能测试和功能测试都是在系统测试阶段运行, 两者有什么区别呢? 案例:豌豆射手和三线射手都是射手, 它们的功能都是向前发射豌豆进行攻击, 能够攻击到地面的僵尸. 但是从性能上来讲, 豌豆射手只能攻击到一路的僵尸, 而三线射手能同时攻击三路(注:放在边路实际…

读天才与算法:人脑与AI的数学思维笔记24_预测性文本生成器

1. 起源 1.1. 人类讲故事可能起源于“假如……”这种问答结构 1.2. 讲故事是人类做安全试验的一种方式 1.2.1. 如果你问一个人“假如……”&#xff0c;其实是在探索你的行为对他可能带来的影响 1.3. 最早出现的故事极有可能就源自我们对在周遭混乱的环境中寻找某种秩序的渴…

基于vgg16和efficientnet卷积神经网络的天气识别系统(pytorch框架)全网首发【图像识别-天气分类】

一个能够从给定的环境图像中自动识别并分类天气&#xff08;如晴天、多云、雨天、雪天闪电等&#xff09;的系统。 技术栈&#xff1a; 深度学习框架&#xff1a;PyTorch基础模型&#xff1a;VGG16与EfficientNet任务类型&#xff1a;计算机视觉中的图像分类 模型选择 VGG16 …

螺栓扭矩如何设计?——SunTorque智能扭矩系统

螺栓扭矩设计的大小是一个涉及工程实践的重要问题&#xff0c;它直接关系到螺栓连接的紧固质量和安全性。螺栓扭矩是工程领域中常用的一个概念&#xff0c;用来描述螺栓在连接过程中所需的旋转力矩。正确的螺栓扭矩可以确保螺栓和螺母之间的紧密连接&#xff0c;避免由于松动而…

JINGWHALE 虚拟现实物质与空间理论 —— 全息世界

JINGWHALE 对此论文相关未知以及已知概念、定理、公式、图片等内容的感悟、分析、创新、创造等拥有作品著作权。未经 JINGWHALE 授权&#xff0c;禁止转载与商业使用。 一、虚拟现实物质与空间理论 物质是由离散的奇点JING粒子&#xff0c;依据不同的维度粒度&#xff0c;通过…

《解锁高效合同管理系统:优化业务流程,提升管理效率》

随着企业规模的扩大和业务复杂性的增加&#xff0c;合同管理变得愈发重要。合同是企业与客户、供应商、合作伙伴之间的法律约束和商业承诺&#xff0c;而有效的合同管理系统则成为企业提高运营效率、降低风险的关键工具。本文将探讨合同管理系统的重要性以及如何利用合同管理系…

网络编程——Socket——模拟用户登录

功能一&#xff1a;模拟用户登录 功能二&#xff1a;实现客户发送登录用户信息&#xff0c;服务器端显示登录信息并响应给客户端登录成功 这里设置的用户登录信息为&#xff1a;admin&#xff0c;123456 实现&#xff1a; 1.首先&#xff0c;服务端创建并启动服务器&#x…

selenium爬取TapTap评论

上一篇写的beautifulsoup和request爬取出的结果有误。首先&#xff0c;TapTap网页以JS格式解析&#xff0c;且评论并没有“下一页”&#xff0c;而是每次加载到底部就要进行等待重新加载。我们需要做的&#xff0c;是模仿浏览器的行为&#xff0c;所以这里我们用Selenium的方式…

STM32_HAL_RTC_中断实现闹钟

1STM32设置 在STM32Cude中设置RTC//具体设置看先前发的文章 再打开闹钟中断&#xff08;如下图&#xff09; 2代码思路 2.1启动闹钟&#xff08;HAL_RTC_SetAlarm_IT(&hrtc,&sAlarm,FORMAT_BCD)&#xff09; 2.2设置回调函数&#xff08;void HAL_RTC_AlarmAEventC…

C++ VScode: launch: program ...... dose not exist

VScode: launch: program … dose not exist 介绍 参考VS Code 配置 C/C 编程运行环境&#xff08;保姆级教程&#xff09;教程配置了VSCode。在配置launch.json适用多个.c 文件编译时&#xff0c;弹出下面错误。 原因和解决方法 是task.json 默认配置的问题。 默认的 cwd参…

内网远程软件哪个好用

内网远程软件哪个好用 在现代化的办公环境中&#xff0c;内网远程软件已成为提高工作效率、实现灵活办公的重要工具。然而&#xff0c;市场上内网远程软件众多&#xff0c;究竟哪个好用呢&#xff1f;本文将为您推荐几款优秀的内网远程软件&#xff0c;并分析其特点&#xff0…