使用opencv实现更换证件照背景颜色

1 概述

生活中经常要用到各种要求的证件照电子版,红底,蓝底,白底等,大部分情况我们只有其中一种,本文通过opencv实现证件照背景的颜色替换。

1.1 opencv介绍

OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。它最初由英特尔在1999年开发,后来由Willow Garage和Itseez(现为部分的Intel)维护。OpenCV旨在提供一个易于使用的计算机视觉基础设施,帮助人们实现复杂的视觉分析任务。

1.2 RGB介绍

RGB 是我们接触最多的颜色空间,由三个通道表示一幅图像,分别为红色(R),绿色(G)和蓝色(B)。这三种颜色的不同组合可以形成几乎所有的其他颜色。

RGB 颜色空间是图像处理中最基本、最常用、面向硬件的颜色空间,比较容易理解。RGB 颜色空间利用三个颜色分量的线性组合来表示颜色,任何颜色都与这三个分量有关,而且这三个分量是高度相关的,所以连续变换颜色时并不直观,想对图像的颜色进行调整需要更改这三个分量才行。

自然环境下获取的图像容易受自然光照、遮挡和阴影等情况的影响,即对亮度比较敏感。而 RGB 颜色空间的三个分量都与亮度密切相关,即只要亮度改变,三个分量都会随之相应地改变,而没有一种更直观的方式来表达。

但是人眼对于这三种颜色分量的敏感程度是不一样的,在单色中,人眼对红色最不敏感,蓝色最敏感,所以 RGB 颜色空间是一种均匀性较差的颜色空间。如果颜色的相似性直接用欧氏距离来度量,其结果与人眼视觉会有较大的偏差。对于某一种颜色,我们很难推测出较为精确的三个分量数值来表示。所以,RGB 颜色空间适合于显示系统,却并不适合于图像处理。

1.3 HSV 颜色空间

基于上述理由,在图像处理中使用较多的是 HSV 颜色空间,它比 RGB 更接近人们对彩色的感知经验。非常直观地表达颜色的色调、鲜艳程度和明暗程度,方便进行颜色的对比。在 HSV 颜色空间下,比 BGR 更容易跟踪某种颜色的物体,常用于分割指定颜色的物体。

HSV 表达彩色图像的方式由三个部分组成:

  • Hue(色调、色相)
  • Saturation(饱和度、色彩纯净度)
  • Value(明度)

用下面这个圆柱体来表示 HSV 颜色空间,圆柱体的横截面可以看做是一个极坐标系 ,H 用极坐标的极角表示,S 用极坐标的极轴长度表示,V 用圆柱中轴的高度表示。

Hue 用角度度量,取值范围为0~360°,表示色彩信息,即所处的光谱颜色的位置。表示如下: 

颜色圆环上所有的颜色都是光谱上的颜色,从红色开始按逆时针方向旋转,Hue=0 表示红色,Hue=120 表示绿色,Hue=240 表示蓝色等等。在 GRB中 颜色由三个值共同决定,比如黄色为即 (255,255,0);在HSV中,黄色只由一个值决定,Hue=60即可。

HSV 圆柱体的半边横截面(Hue=60):

 其中水平方向表示饱和度,饱和度表示颜色接近光谱色的程度。饱和度越高,说明颜色越深,越接近光谱色饱和度越低,说明颜色越浅,越接近白色。饱和度为0表示纯白色。取值范围为0~100%,值越大,颜色越饱和。

竖直方向表示明度,决定颜色空间中颜色的明暗程度,明度越高,表示颜色越明亮,范围是 0-100%。明度为0表示纯黑色(此时颜色最暗)。

可以通俗理解为:

在Hue一定的情况下,饱和度减小,就是往光谱色中添加白色,光谱色所占的比例也在减小,饱和度减为0,表示光谱色所占的比例为零,导致整个颜色呈现白色。

明度减小,就是往光谱色中添加黑色,光谱色所占的比例也在减小,明度减为0,表示光谱色所占的比例为零,导致整个颜色呈现黑色。

HSV 对用户来说是一种比较直观的颜色模型。我们可以很轻松地得到单一颜色,即指定颜色角H,并让V=S=1,然后通过向其中加入黑色和白色来得到我们需要的颜色。增加黑色可以减小V而S不变,同样增加白色可以减小S而V不变。例如,要得到深蓝色,V=0.4 S=1 H=240度。要得到浅蓝色,V=1 S=0.4 H=240度。

HSV 的拉伸对比度增强就是对 S 和 V 两个分量进行归一化(min-max normalize)即可,H 保持不变。

RGB颜色空间更加面向于工业,而HSV更加面向于用户,大多数做图像识别这一块的都会运用HSV颜色空间,因为HSV颜色空间表达起来更加直观!

1.4 HLS 颜色空间

HLS 和 HSV 比较类似,这里一起介绍。HLS 也有三个分量,hue(色相)、saturation(饱和度)、lightness(亮度)。

HLS 和 HSV 的区别就是最后一个分量不同,HLS 的是 light(亮度),HSV 的是 value(明度)。

HLS 中的 L 分量为亮度,亮度为100,表示白色,亮度为0,表示黑色;HSV 中的 V 分量为明度,明度为100,表示光谱色,明度为0,表示黑色。

下面是 HLS 颜色空间圆柱体:

提取白色物体时,使用 HLS 更方便,因为 HSV 中的Hue里没有白色,白色需要由S和V共同决定(S=0, V=100)。而在 HLS 中,白色仅由亮度L一个分量决定。所以检测白色时使用 HSL 颜色空间更准确。

注意:在 OpenCV 中 HLS 三个分量的范围为:

  • H = [0,179]
  • L = [0,255]
  • S = [0,255]

2 使用opencv替换证件照背景颜色

2.1 导入图片并改变图片大小

原始图片:

代码实现:

img = cv2.imread('../data/card_girl01.jpeg')# 缩放
rows, cols, channels = img.shape
img = cv2.resize(img, None, fx=0.5, fy=0.5)
rows, cols, channels = img.shape

2.2 获取背景区域

首先将读取的图像默认BGR格式转换为HSV格式,然后通过inRange函数获取背景的mask。

代码实现:

# 转换hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_blue = np.array([78, 43, 46])
upper_blue = np.array([110, 255, 255])
mask_img = cv2.inRange(hsv, lower_blue, upper_blue)new_image = show_multi_imgs(4, [img, cv2.cvtColor(mask_img, cv2.COLOR_GRAY2BGR)], (1, 2))
cv2.namedWindow('img&mask_img', 0)
cv2.imshow('img&mask_img', new_image)
cv2.waitKey(0)

运行代码显示:

如图所示蓝色的背景在图中用白色表示,白色区域就是要替换的部分,但是黑色区域内有白点干扰,所以进一步优化。

2.3 腐蚀和膨胀

代码实现:

# 腐蚀膨胀
erode_img = cv2.erode(mask_img, None, iterations=1)new_image = show_multi_imgs(4, [img, cv2.cvtColor(erode_img, cv2.COLOR_GRAY2BGR)], (1, 2))
cv2.namedWindow('img&erode_img', 0)
cv2.imshow('img&erode_img', new_image)
cv2.waitKey(0)dilate_img = cv2.dilate(erode_img, None, iterations=1)
new_image = show_multi_imgs(4, [img, cv2.cvtColor(dilate_img, cv2.COLOR_GRAY2BGR)], (1, 2))
cv2.namedWindow('img&dilate_img', 0)
cv2.imshow('img&dilate_img', new_image)
cv2.waitKey(0)

运行代码显示:

处理后图像单独白色点消失。

2.4 替换背景色

遍历全部像素点,如果该颜色为dilate里面为白色(255)则说明该点所在背景区域,于是在原图img中进行颜色替换。

示例代码:

# 遍历替换
final_img = img.copy()
for i in range(rows):for j in range(cols):if dilate_img[i, j] == 255:# 此处替换颜色,为BGR通道final_img[i, j] = (0, 0, 255)new_image = show_multi_imgs(4, [img, final_img], (1, 2))
cv2.namedWindow('img&final_img', 0)
cv2.imshow('img&final_img', new_image)
cv2.waitKey(0)

 运行代码显示:

2.5 完整代码

import cv2
import numpy as np# 一个窗口显示多张图片
def show_multi_imgs(scale, imglist, order=None, border=10, border_color=(255, 255, 0)):""":param scale: float 原图缩放的尺度:param imglist: list 待显示的图像序列:param order: list or tuple 显示顺序 行×列:param border: int 图像间隔距离:param border_color: tuple 间隔区域颜色:return: 返回拼接好的numpy数组"""if order is None:order = [1, len(imglist)]allimgs = imglist.copy()ws, hs = [], []for i, img in enumerate(allimgs):if np.ndim(img) == 2:allimgs[i] = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)allimgs[i] = cv2.resize(img, dsize=(0, 0), fx=scale, fy=scale)ws.append(allimgs[i].shape[1])hs.append(allimgs[i].shape[0])w = max(ws)h = max(hs)# 将待显示图片拼接起来sub = int(order[0] * order[1] - len(imglist))# 判断输入的显示格式与待显示图像数量的大小关系if sub > 0:for s in range(sub):allimgs.append(np.zeros_like(allimgs[0]))elif sub < 0:allimgs = allimgs[:sub]imgblank = np.zeros(((h+border) * order[0], (w+border) * order[1], 3)) + border_colorimgblank = imgblank.astype(np.uint8)for i in range(order[0]):for j in range(order[1]):imgblank[(i * h + i*border):((i + 1) * h+i*border), (j * w + j*border):((j + 1) * w + j*border), :] = allimgs[i * order[1] + j]return imgblankimg = cv2.imread('../data/card_girl01.jpeg')# 缩放
rows, cols, channels = img.shape
img = cv2.resize(img, None, fx=0.5, fy=0.5)
rows, cols, channels = img.shape# 转换hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_blue = np.array([78, 43, 46])
upper_blue = np.array([110, 255, 255])
mask_img = cv2.inRange(hsv, lower_blue, upper_blue)new_image = show_multi_imgs(4, [img, cv2.cvtColor(mask_img, cv2.COLOR_GRAY2BGR)], (1, 2))
cv2.namedWindow('img&mask_img', 0)
cv2.imshow('img&mask_img', new_image)
cv2.waitKey(0)# 腐蚀膨胀
erode_img = cv2.erode(mask_img, None, iterations=1)new_image = show_multi_imgs(4, [img, cv2.cvtColor(erode_img, cv2.COLOR_GRAY2BGR)], (1, 2))
cv2.namedWindow('img&erode_img', 0)
cv2.imshow('img&erode_img', new_image)
cv2.waitKey(0)dilate_img = cv2.dilate(erode_img, None, iterations=1)
new_image = show_multi_imgs(4, [img, cv2.cvtColor(dilate_img, cv2.COLOR_GRAY2BGR)], (1, 2))
cv2.namedWindow('img&dilate_img', 0)
cv2.imshow('img&dilate_img', new_image)
cv2.waitKey(0)# 遍历替换
final_img = img.copy()
for i in range(rows):for j in range(cols):if dilate_img[i, j] == 255:# 此处替换颜色,为BGR通道final_img[i, j] = (0, 0, 255)new_image = show_multi_imgs(4, [img, final_img], (1, 2))
cv2.namedWindow('img&final_img', 0)
cv2.imshow('img&final_img', new_image)
cv2.waitKey(0)

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

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

相关文章

UI上传组件异步上传更改为同步

实现异步方法 JavaScript 异步 实现异步的五种实现方法_js异步-CSDN博客 这两种比较经常用。 因为上传组件是异步上传的通过Async和await配合使用可以上传完照片视频后返回的地址在继续走下去&#xff0c;而不是图片视频地址还未获取时就上传后端了。

java文件上传以及使用阿里云OSS

JavaWeb 文件上传本地存储阿里云OSS配置文件 yml配置文件 文件上传 前端页面三要素&#xff1a; 表单项type“file” 表单提交方式post 表单的enctype属性multipart/form-data 本地存储 保证上传的文件不重复 //获取原始文件名String originalFilename image.getOriginalFi…

计算机毕业设计 基于PHP的考研互助交流系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

机器学习笔记 - 基于百度飞桨PaddleSeg的人体分割

一、简述 虽然Segment Anything用于图像分割的通用大模型看起来很酷(飞桨也提供分割一切的模型),但是个人感觉落地应用的时候心里还是更倾向于飞桨这种场景式的,因为需要用到一些人体分割的需求,所以这里主要是对飞桨高性能图像分割开发套件进行了解和使用,但是暂时不训练…

day64 django中间件的复习使用

django中间件 django中间件是django的门户 1.请求来的时候需要先经过中间件才能达到真正的django后端 2.响应走的时候也需要经过中间件 ​ djangp自带七个中间件MIDDLEWARE [django.middleware.security.SecurityMiddleware,django.contrib.sessions.middleware.SessionMiddle…

解决Maven项目jar包下载失败的问题

文章目录 配置国内的Maven源引入正确的settings.xml文件重新下载jar包对后面要创建的新项目也统一配置仍然失败的解决办法 配置国内的Maven源 引入正确的settings.xml文件 如果该目录下的 settings.xml文件不存在或者错误&#xff0c;要创建一个 settings.xml文件并写入正确的…

Java 常用容器

目录 列表栈&#xff08;类&#xff09;队列(接口)setMap 列表 package com.czl;import java.util.ArrayList; import java.util.List; //AltEnter导入包 public class Main {public static void main(String[] args) throws Exception{List<Integer> list new ArrayLis…

这个变量要不要用volatile修饰呢?

正文 大家好&#xff0c;又见面了&#xff0c;我是bug菌~ 在嵌入式软件开发过程中&#xff0c;如果对volatile不熟&#xff0c;那可以你应该是个"假嵌入式程序员"&#xff0c;因为一个变量需不需要使用volatile考虑的场景挺多的&#xff0c;如果在某些场景下乱用&…

读像火箭科学家一样思考笔记12_实践与测试(下)

1. 舆论的火箭科学 1.1. 如果苹果违反了“即飞即测”原则&#xff0c;那苹果的iPhone就不会问世了 1.1.1. iPhone在其上市前的民意调查中相当失败 1.1.1.1. iPhone不可能获得太大市场份额&#xff0c;不可能。 1.1.1.1.1. 微软前CEO史蒂夫鲍尔默&#xff08;Steve Ballmer&…

第15关 K8s HPA:自动水平伸缩Pod,实现弹性扩展和资源优化

------> 课程视频同步分享在今日头条和B站 大家好&#xff0c;我是博哥爱运维&#xff0c;这节课带来k8s的HPA 自动水平伸缩pod&#xff08; 视频后面有彩蛋 : ) &#xff09;。 我们知道&#xff0c;初始Pod的数量是可以设置的&#xff0c;同时业务也分流量高峰和低峰&a…

Deep Image Prior

深度图像先验 论文链接&#xff1a;https://sites.skoltech.ru/app/data/uploads/sites/25/2018/04/deep_image_prior.pdf 项目链接&#xff1a;https://github.com/DmitryUlyanov/deep-image-prior Abstract 深度卷积网络已经成为一种流行的图像生成和恢复工具。一般来说&a…

每日一练2023.11.28———N个数求和【PTA】

题目链接&#xff1a; L1-009 N个数求和 题目要求&#xff1a; 本题的要求很简单&#xff0c;就是求N个数字的和。麻烦的是&#xff0c;这些数字是以有理数分子/分母的形式给出的&#xff0c;你输出的和也必须是有理数的形式。 输入格式&#xff1a; 输入第一行给出一个正整…

三 STM32F4使用Sys_Tick 实现微秒定时器和延时

更多细节参考这篇 1. 什么是时钟以及作用 1.1 什么是时钟 时钟是由电路产生的周期性的脉冲信号&#xff0c;相当于单片机的心脏 1.2 时钟对于STM32的作用 指令同步&#xff1a;cpu和内核外设使用时钟信号来进行指令同步数据传输控制&#xff1a; 时钟信号控制数据在内部总…

【C数据(一)】数据类型和变量你真的理解了吗?来看看这篇

&#x1f308;write in front :&#x1f50d;个人主页 &#xff1a; 啊森要自信的主页 ✏️真正相信奇迹的家伙&#xff0c;本身和奇迹一样了不起啊&#xff01; 欢迎大家关注&#x1f50d;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;>希望看完我的文章对你有小小的帮助&am…

Linux的Sysfs 接口

一、sysfs接口 在linux系统中&#xff0c;用户空间访问驱动程序一般是以“设备文件”的方式通过“read/write/ioctl”访问&#xff0c;还有一种方式&#xff0c;可以通过echo的方式来直接控制硬件或者修改驱动&#xff0c;也能为底层驱动提供一个接口便于应用层调用&#xff0c…

app上架一直显示审核中状态要怎么处理?

当你提交一个应用到App Store上时&#xff0c;它会经历一个审核过程。在这个过程中&#xff0c;苹果的审核人员会检查你的应用是否符合苹果的规定和标准。这个过程通常需要几天的时间&#xff0c;但是如果你的应用一直显示“审核中”状态&#xff0c;那么可能会有一些原因。 1…

广州华锐互动:VR虚拟现实内容创作工具带来全新的应用场景

随着科技的不断发展&#xff0c;低代码编辑工具已经成为了一种越来越受欢迎的开发方式。它可以帮助开发人员快速构建应用程序&#xff0c;降低开发成本&#xff0c;提高开发效率&#xff0c;而VR虚拟现实内容创作工具带来了全新的应用场景。 VR虚拟现实内容创作工具是广州华锐互…

AlphaFold的原理及解读

1、背景 蛋白质是生物体内一类重要的生物大分子&#xff0c;其结构复杂多样&#xff0c;蛋白质的结构对于理解其功能和参与的生物学过程具有重要意义。从生物学角度上看&#xff0c;蛋白质的结构可以分为四个层次&#xff1a;初级结构、二级结构、三级结构和四级结构。 初级结…

模拟实现offsetof宏(详解)

我们在以前学过这个offsetof函数&#xff0c;知道它的功能是求指针相较于起始位置的偏移量&#xff0c;我们今天要来写出一个宏&#xff0c;计算结构体中某成员变量相对于起始位置的偏移。 目录 1.offsetof函数 1.1offsetof函数介绍 1.2offsetof函数代码实现 2.offsetof函数…

python实现rpc的几种方式(SimpleXMLRPCServer 自带的、第三方ZeroRPC)、连接linux远程开发分布式锁、分布式id

1 python实现rpc的几种方式 1.1 SimpleXMLRPCServer 自带的 1.2 第三方ZeroRPC 2 连接linux远程开发 3 分布式锁 4 分布式id 1 python实现rpc的几种方式 # 远程过程调用-1 借助于rabbitmq,可以跨语言-2 SimpleXMLRPCServer 自带的-3 ZeroRPC-4 GRPC&#xff1a;跨语言的 htt…