基于RGB颜色空间使用OpenCV-Python实现照片换底

☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython

一、引言

前一阵子家人报考教师资格证考试,因报名需要将蓝底的数字相片换成白底的,老猿虽然在学习图像处理相关开发技术,但并没有熟练使用的图像编辑软件,一般也就是用个windows的画图工具简单处理一下,因此这个事情就只好求助于OpenCV的图像处理技术。不过老猿OpenCV图像处理也就学了最低级的图像处理,其他的还没学完,也就会图像空间变换、腐蚀和膨胀处理、阈值处理、几何变换、四则运算、鼠标键盘事件等。具体请参考《OpenCV-Python图形图像处理》。

二、处理思路

2.1、初步思路

老猿试图用学过的图像处理基础知识能完成数字图像的处理,大致构思如下:

  1. 先将图像分离为R、G、B三通道的三个图像,蓝底应该是R、G分量小B分量较大的部分,分别对这三部分进行阈值处理(R、G分量小于某个值,B分量要求大于某个值),满足这样条件的我们就认为该像素对应区域为背景色区域,阈值处理后可以得到背景的掩膜图像A以及其反转后对应前景色的掩膜图像F
  2. 将原照片自身与自身相乘,相乘时设置其掩膜为掩膜图像F,得到照片前景;
  3. 构造一与照片大小相同的纯白色(新底色)图像,将其自身与自身相乘,相乘时设置其掩膜为掩膜图像A,得到对应的新底色背景;
  4. 将新得到的照片前景和新底色背景相加或相或得到新底色的照片。
2.3、实际处理遇到的问题及应对

实际处理时,发现远比这个复杂,有2个问题:

  • 照片的背景色不是单一的像素值,而是不同位置会有不同,特别是前景色周边的灰度值与其他部分差异较大;
  • 背景色的灰度值与前景色的灰度值不是简单的大于等于或小于等于关系,而是部分前景色小于背景色灰度值,部分前景色灰度值大于背景色灰度值,甚至有部分灰度值前景色和背景色是相同的。

在这个时候就需要根据实际相片底色情况调整RGB三个分量阈值处理的阈值,需要能对未能有效识别为背景区域的背景区域方便获取对应像素值。同时为了解决边界问题,可能需要进行背景色的膨胀处理。

2.4、代码实现

按照以上处理思路和问题应对方式,老猿实现了一个图像鼠标点击获取像素值输出的函数和一个图像背景色替换的函数,代码如下:

import cv2
import numpy as np
from opencvPublic import readImgFile #类似imread的图片文件装载函数,支持识别中文文件名

def OnMouseEvent( event, x, y, flags,img):#图片点击时输出对应位置和像素值
    #鼠标左键按下打印对应位置的图像的像素值
    if event==cv2.EVENT_LBUTTONDOWN:
        print(f'{(x,y)}:{img[y][x]}')

def changePhotoBG(fileName,BGRThresh,MorphOpCount=0):
    photo = readImgFile(fileName)  #读入图像
    BThresh,GThresh,RThresh = BGRThresh
    bgWhite = np.full(photo.shape[:],255,dtype=np.uint8) #构造一个与图像大小完全相同的全白图像

    #分离读入图像的rgb分量,并对每个分量进行阈值处理,确认每个分量的阈值是最关键的一步,与具体图像背景紧密相关,根据背景调整相关阈值
    b,g,r = cv2.split(photo)
    ret, maskb = cv2.threshold(b, BThresh, 255, cv2.THRESH_BINARY)  
    ret,maskg  = cv2.threshold(g, GThresh, 255, cv2.THRESH_BINARY)
    ret, maskr = cv2.threshold(r,RThresh, 255, cv2.THRESH_BINARY)


    #因要替换蓝色底,因此需要判断哪些像素是蓝底像素,判断时,要求经过阈值处理的G、R分量为0,B分量为255
    # 把符合此要求的灰度图作为处理图像的掩膜就能得到输入图像的背景色区域
    #如果要处理非蓝底的,则需要进行下面两行代码的修改将非底色的其他两个颜色的掩膜相或后求反,再与底色的掩膜相与
    maskrg = cv2.bitwise_not(cv2.bitwise_or(maskr,maskg))
    maskbgr = cv2.bitwise_and(maskb,maskrg)

    #由于在边界位置可能存在像素值情况可能与其他背景色不同的情况,因此可能需要进行背景掩膜的扩展膨胀(MORPH_DILATE)处理,且迭代次数可能也有不同,视具体图像而定

    if MorphOpCount:#背景色掩膜进行扩张处理
        kernal = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
        maskbgr = cv2.morphologyEx(maskbgr, cv2.MORPH_DILATE , kernal, iterations=MorphOpCount)


    #获得背景掩膜的反图像得到前景掩膜
    maskbgrInv = cv2.bitwise_not(maskbgr)

    #获取背景掩膜对应的白色背景对应图像
    bgWhite = cv2.bitwise_and(bgWhite, bgWhite, mask=maskbgr)

    #将输入图像应用前景掩膜,得到输入图像的前景,并将该前景与掩膜处理后的白色背景相叠加获得最后处理图像
    photoFront = cv2.bitwise_and(photo,photo,mask=maskbgrInv)
    result = cv2.bitwise_or(photoFront,bgWhite)

    #显示处理图像并设置鼠标回调函数,当出现未完全处理好的噪点时,通过鼠标获得该噪点位置的像素值,以调整前面的阈值处理的阈值
    cv2.imshow('pic',result)
    cv2.setMouseCallback('pic', OnMouseEvent,result)

    cv2.waitKey(0)

使用的自定义公用模块函数readImgFile,其功能请参考《https://blog.csdn.net/LaoYuanPython/article/details/111351901 OpenCV-Python图形图像处理:自用的一些工具函数功能及调用语法介绍》中的介绍。

三、测试过程

3.1、处理图片说明

本次介绍以百度“蓝底相片”找到的图片(如果涉及侵权请博客留言处理)作为处理对象介绍:
在这里插入图片描述

2、获取图像的背景色的阈值

怎么来确认R、G、B的阈值呢?网上有蓝底相片RGB值的多种说法,一方面太过理想化,另一方面说法还矛盾,怎么办呢?其实很简单,相片的左上角一般为底色,将图像加载后,看前几个像素的R、G、B值,让其作为参考阈值上下浮动一下。上述照片的前几个像素值如下:
在这里插入图片描述
可以看到前几个像素的B、G、R分量中B大于等于238、G小于等于115、R小于等于57,注意阈值处理函数在type为THRESH_BINARY时是小于等于阈值时为0,否则为指定最大值。

3、以前几个像素值作为参考来设定阈值

我们以B、G、R分别设置为237、115、57来设置阈值,不进行膨胀处理来调用上面实现的changePhotoBG函数来看看效果。
执行:changePhotoBG(r'f:\pic\girl.jpg',(237,115,57))

处理效果:
在这里插入图片描述
可以看到在涉及图像边界时处理效果不好,需要叠加背景色的扩展处理,对应调用为:

changePhotoBG(r'f:\pic\girl.jpg',(237,115,57),1)
changePhotoBG(r'f:\pic\girl.jpg',(237,115,57),2)
changePhotoBG(r'f:\pic\girl.jpg',(237,115,57),3)
changePhotoBG(r'f:\pic\girl.jpg',(237,115,57),5)

下图四张照片从上到下、从左到右对应分别做了1、2、3、5次膨胀后的结果图像:
在这里插入图片描述
可以看到膨胀5次以后基本上正常了,但还有一点点边界蓝色,再膨胀的话图片人像就会失真。
点击上述图片蓝色地方,看到输出的像素值如下:

(229, 266):[237 123  62]
(263, 116):[235 117  65]
(104, 269):[207 116  77]

因此根据这些输出调整BGR三个分量的值,将调用改为:changePhotoBG(r'f:\pic\girl.jpg',(206,123,77),3),可以得到如下图像:
在这里插入图片描述
可以看到效果相当不错了,老猿就没有再调整了。

四、小结

本文介绍了基于BGR颜色空间给蓝底照片换底的实现思路及程序代码,并将相关代码做成了一个比较通用的函数,只需要根据照片的背景色调整底色识别的B、G、R三个分量的阈值,就可以适应不同蓝色的背景色的照片情况,如果要处理非蓝底的,就需要将函数中求背景掩膜的两行代码相应进行调整。

本文代码测试完成并写完博文后,在网上找到了一篇类似功能介绍的博文,不过是基于HSV空间的,因此在标题中特地加上“基于RGB颜色空间”。过2天老猿将基于HSV的实现方式也写出,并提供参考博文对照一下。大家可以这2种颜色空间的实现方式都参考一下。具体博文请见《基于HSV颜色空间用OpenCV-Python给照片换底》。

更多图像处理的内容请参考专栏《OpenCV-Python图形图像处理 https://blog.csdn.net/laoyuanpython/category_9979286.html》、《https://blog.csdn.net/laoyuanpython/category_10581071.html OpenCV-Python初学者疑难问题集》及《图像处理基础知识》的介绍。

如对文章内容存在疑问,可在博客评论区留言,或关注老猿Python 微信公号发消息咨询。
在这里插入图片描述

关于老猿的付费专栏

  1. 付费专栏《https://blog.csdn.net/laoyuanpython/category_9607725.html 使用PyQt开发图形界面Python应用》专门介绍基于Python的PyQt图形界面开发基础教程,对应文章目录为《 https://blog.csdn.net/LaoYuanPython/article/details/107580932 使用PyQt开发图形界面Python应用专栏目录》;
  2. 付费专栏《https://blog.csdn.net/laoyuanpython/category_10232926.html moviepy音视频开发专栏 )详细介绍moviepy音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,对应文章目录为《https://blog.csdn.net/LaoYuanPython/article/details/107574583 moviepy音视频开发专栏文章目录》;
  3. 付费专栏《https://blog.csdn.net/laoyuanpython/category_10581071.html OpenCV-Python初学者疑难问题集》为《https://blog.csdn.net/laoyuanpython/category_9979286.html OpenCV-Python图形图像处理 》的伴生专栏,是笔者对OpenCV-Python图形图像处理学习中遇到的一些问题个人感悟的整合,相关资料基本上都是老猿反复研究的成果,有助于OpenCV-Python初学者比较深入地理解OpenCV,对应文章目录为《https://blog.csdn.net/LaoYuanPython/article/details/109713407 OpenCV-Python初学者疑难问题集专栏目录
  4. 付费专栏《https://blog.csdn.net/laoyuanpython/category_10762553.html Python爬虫入门 》站在一个互联网前端开发小白的角度介绍爬虫开发应知应会内容,包括爬虫入门的基础知识,以及爬取CSDN文章信息、博主信息、给文章点赞、评论等实战内容。

前两个专栏都适合有一定Python基础但无相关知识的小白读者学习,第三个专栏请大家结合《https://blog.csdn.net/laoyuanpython/category_9979286.html OpenCV-Python图形图像处理 》的学习使用。

对于缺乏Python基础的同仁,可以通过老猿的免费专栏《https://blog.csdn.net/laoyuanpython/category_9831699.html 专栏:Python基础教程目录)从零开始学习Python。

如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。

老猿Python, 跟老猿学Python!

☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython

老猿Python,跟老猿学Python!

☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython
  • 15
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
### 回答1: 你好!OpenCV-Python-Headless是一种无界面的版本,可用于运行在服务器上的计算机视觉应用程序。它的用法和OpenCV-Python类似,但是在使用时不会显示图像。这对于运行在无图形界面的服务器上的应用程序很方便,因为它可以节省资源。 要使用OpenCV-Python-Headless,首先需要安装它。你可以使用pip命令安装: ``` pip install opencv-python-headless ``` 然后,在你的Python代码中导入cv2库,就像使用OpenCV-Python一样: ``` import cv2 ``` 在你的代码中使用OpenCV的功能时,就可以像平常一样使用了。 希望这能帮到你! ### 回答2: opencv-python-headless 是 OpenCV 在 Python 环境中的一个无界面版本,相比于完整版的 OpenCV,它不需要额外安装 GUI 库或对显示器的依赖,因此适用于各种后台或服务器应用。使用 opencv-python-headless,我们可以在无图形界面的环境中对图像和视频进行处理。 要使用 opencv-python-headless,我们首先需要在 Python 中安装它。可以通过 pip 命令来安装: ```python pip install opencv-python-headless ``` 安装完成后,我们可以在 Python 中导入 `cv2` 模块来使用 opencv-python-headless。与完整版的 OpenCV 不同,无界面版本没有图形窗口的显示功能,因此我们需要使用其他方法来检查和显示处理结果。 一种常见的方法是将结果保存为图像或视频文件,在需要时再进行查看。我们可以使用 `cv2.imwrite()` 方法将图像保存到指定的路径: ```python import cv2 image = cv2.imread('image.jpg') # 进行图像处理操作 cv2.imwrite('output.jpg', image) ``` 另一种方法是使用 Matplotlib 库来显示图像。Matplotlib 不需要图形界面,可以在 Python 脚本中显示图像: ```python import cv2 import matplotlib.pyplot as plt image = cv2.imread('image.jpg') # 进行图像处理操作 plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) plt.show() ``` 除了图像处理,opencv-python-headless 还提供了对视频文件的处理功能。我们可以使用 `cv2.VideoCapture()` 来读取视频文件,然后使用 `cv2.VideoWriter()` 来保存处理后的视频。 总之,opencv-python-headless 是一个适用于无界面环境的 OpenCV 版本,通过安装和使用合适的库和方法,我们可以在 Python 中使用它进行图像和视频的处理,并根据需要保存或显示处理结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LaoYuanPython

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值