目录
- python使用opencv换照片底色
- 安装问题
- 使用opencv及原理
- python opencv一键换底色,不同底色自动判断
- 思路来源
- 需求
- 预览
- 对比
- 总结
python使用opencv换照片底色
第一次使用opencv,遇到了很多问题,记录一下
安装问题
代理
由于pip使用了代理而电脑代理没开,导致pip install opencv-python时一直报错连接不上代理
解决办法:
- 1.使用pip install -i <清华源>
- 2.开启代理
无法引入jar包
安装完成后在交互模式可以正常使用
输入python
import cv
不报错就说明正常安装了
但是在jupyter notebook 中引入一直报错,找不到cv2模块
经过百度后,测试如下
在交互模式下输入如下命令查看python环境
import sys | |
sys.executable |
这是anaconda下的一个虚拟环境,没有问题
再在jupyter notebook下输入同样的命令,查看python环境,发现竟然不是上述环境
而是 anaconda3/share下的环境
至此,就查询到了问题的原因:
jupyter notebook 是anaconda的公共包
进入虚拟环境后 pip install jupyter 再次启动jupyter notebooke 就正常了
使用opencv及原理
使用opencv换照片底色的原理很简单
- 读取照片
- 将照片转换为灰度图
- 提取灰度图底色的BGR上下边界
- 使用opencv转换背景底色的BGR值(第三步已经获取了背景色的上下边界,边界之中的所有颜色都会被转换为255,边界之外的颜色都会被处理为0)
- 循环处理像素点,将第四步转换后的255(背景色)转换为你想要的颜色
- 输出,保存
import cv | |
import numpy as np | |
# 读取照片 | |
img=cv.imread('zhuominghua.jpg') | |
# 图像缩放 | |
img = cv.resize(img,None,fx=0.5,fy=0.5) | |
rows,cols,channels = img.shape | |
print(rows,cols,channels) | |
cv.imshow('[img]',img) | |
# 图片转换为灰度图 | |
hsv = cv.cvtColor(img,cv2.COLOR_BGR2HSV) | |
# 查看灰度图 | |
cv.imshow('hsv',hsv) | |
# 图片的二值化处理 | |
lower_blue=np.array([,0,200]) | |
upper_blue=np.array([,255,255]) | |
mask = cv.inRange(hsv, lower_blue, upper_blue) | |
print(mask) | |
#腐蚀膨胀 | |
erode=cv.erode(mask,None,iterations=1) | |
# cv.imshow('erode',erode) | |
dilate=cv.dilate(erode,None,iterations=1) | |
# cv.imshow('dilate',dilate) | |
#遍历每个像素点,进行颜色的替换 | |
for i in range(rows): | |
for j in range(cols): | |
if erode[i,j]==: # 像素点为255表示的是白色,我们就是要将白色处的像素点,替换为红色 | |
img[i,j]=(,255,255) # 此处替换颜色,为BGR通道,不是RGB通道 | |
# 显示处理后的图片 | |
cv.imshow('res',img) | |
# 保存 | |
cv.imwrite("zhuominghu_white.jpg", img) | |
# 窗口等待的命令,表示无限等待 | |
cv.waitKey(0) |
代码是参照网上的例子,经过实验,很好用
但是在图片的二值化处理阶段,比较麻烦,需要从灰度图中获取背景色的BGR值,再计算上下边界
灰度图的颜色使用BGR表示的,而不是 RGB
使用的到方法:
- imread() 读取源图片
- imshow() 展示图片
- imwrite() 输出图片
- cvtColor() 转换灰度图
- inRange() 二值化处理,将上下边界内的颜色值处理为255,其他的颜色值处理为0
python opencv一键换底色,不同底色自动判断
图来源于网络,未有冒犯之意
思路来源
最近到处需要用到一寸照,但是有些底色不同,一开始网上随便找了几个,但是完成后都是要收费的,后面用到removebg,抠图一键换底色,但是有像素限制,高像素需要收费下载,所以自己无聊用参考网上资料opencv写了个,网上都是单个颜色处理,并且对于参数有些有限制,在细节处理上不通用,所以自己重新写了一个并简单做了个界面,虽然比removebg差多了,不过好歹能用。
需求
- 懒人式换一寸照底色
- 界面应用
- 多底色选择
- 自动识别底色
- 学习代码使用,要求不高
预览
对比
原图
红底
绿底
白底
代码
# -*- coding: utf- -*- | |
# Form implementation generated from reading ui file 'untitled.ui' | |
# | |
# Created by: PyQt UI code generator 5.13.0 | |
# | |
# WARNING! All changes made in this file will be lost! | |
import sys | |
from PyQt import QtCore, QtGui, QtWidgets | |
from PyQt.QtWidgets import QApplication, QMainWindow, QMessageBox,QInputDialog,QFileDialog | |
import cv,time,sys | |
import numpy as np | |
def change_bg_color(path,color): | |
global new_path | |
color_dict={'red':[,0,255],'green':[0,255,0],'blue':[255,0,0],'white':[255,255,255]} | |
color_list=color_dict[color] | |
#导入图片,不能有中文路径 | |
# img=cv.imread(path) | |
#导入图片,可以有中文路径 | |
img = cv.imdecode(np.fromfile(path, dtype=np.uint8), 1) | |
#图片缩放 | |
#img=cv.resize(img,None,fx=0.5,fy=0.5) | |
#转换hsv,提取颜色 | |
#cv.cvtColor是颜色空间转换函数,img是需要转换的图片,第二个是转换成何种格式。 | |
hsv=cv.cvtColor(img,cv2.COLOR_BGR2HSV) | |
#判断当前图片底色 | |
if img[][0][0]>200 and img[0][0][1]<230 and img[0][0][2]<230: | |
# print('原图蓝色底') | |
#提取颜色区域,不在范围的设为,在范围的设为255 | |
hsv_min=np.array([,79,79]) | |
hsv_max=np.array([,255,255]) | |
elif img[][0][1]>200 and img[0][0][0]<230 and img[0][0][2]<230: | |
# print('原图绿色底') | |
hsv_min = np.array([,40,41]) | |
hsv_max = np.array([,255,255]) | |
elif img[][0][2]>200 and img[0][0][0]<230 and img[0][0][1]<230: | |
# print('原图红色底') | |
hsv_min = np.array([,200,40]) | |
hsv_max = np.array([,255,255]) | |
else: | |
# print('原图白色底') | |
hsv_min = np.array([,0,221]) | |
hsv_max = np.array([,30,255]) | |
mask = cv.inRange(hsv, hsv_min, hsv_max) | |
# #腐蚀膨胀 | |
erode=cv.erode(mask,None,iterations=1) | |
dilate=cv.dilate(erode,None,iterations=1) | |
# cv.imshow('res',dilate) | |
rows,cols,channels = img.shape | |
#遍历替换 | |
for i in range(rows): | |
for j in range(cols): | |
if dilate[i,j]==: | |
img[i,j]=(color_list[],color_list[1],color_list[2])#此处替换颜色,为BGR通道 | |
new_path='%s_%s.jpg'%(str(int(time.time())),color) | |
path=path.replace(path.split('/')[-],new_path) | |
new_path=path | |
#防止中文路径 | |
cv.imencode('.jpg',img)[1].tofile(path) | |
# cv.imwrite(path,img) | |
# cv.imshow('res',img) | |
# cv.waitKey(0) | |
# cv.destroyAllWindows() | |
class Ui_MainWindow(object): | |
def setupUi(self, MainWindow): | |
MainWindow.setObjectName("MainWindow") | |
MainWindow.resize(, 600) | |
self.centralwidget = QtWidgets.QWidget(MainWindow) | |
self.centralwidget.setObjectName("centralwidget") | |
self.pushButton = QtWidgets.QPushButton(self.centralwidget) | |
self.pushButton.setGeometry(QtCore.QRect(, 0, 251, 331)) | |
self.pushButton.setObjectName("pushButton") | |
self.pushButton.clicked.connect(self.openFile) | |
self.pushButton_ = QtWidgets.QPushButton(self.centralwidget) | |
self.pushButton_.setGeometry(QtCore.QRect(140, 390, 101, 51)) | |
self.pushButton_.setObjectName("pushButton_2") | |
self.pushButton_.clicked.connect(lambda:self.setimg_bg("blue")) | |
self.pushButton_ = QtWidgets.QPushButton(self.centralwidget) | |
self.pushButton_.setGeometry(QtCore.QRect(280, 390, 101, 51)) | |
self.pushButton_.setObjectName("pushButton_3") | |
self.pushButton_.clicked.connect(lambda:self.setimg_bg("green")) | |
self.pushButton_ = QtWidgets.QPushButton(self.centralwidget) | |
self.pushButton_.setGeometry(QtCore.QRect(430, 390, 101, 51)) | |
self.pushButton_.setObjectName("pushButton_4") | |
self.pushButton_.clicked.connect(lambda:self.setimg_bg("red")) | |
self.pushButton_ = QtWidgets.QPushButton(self.centralwidget) | |
self.pushButton_.setGeometry(QtCore.QRect(570, 390, 101, 51)) | |
self.pushButton_.setObjectName("pushButton_5") | |
self.pushButton_.clicked.connect(lambda:self.setimg_bg("white")) | |
MainWindow.setCentralWidget(self.centralwidget) | |
self.menubar = QtWidgets.QMenuBar(MainWindow) | |
self.menubar.setGeometry(QtCore.QRect(, 0, 800, 26)) | |
self.menubar.setObjectName("menubar") | |
MainWindow.setMenuBar(self.menubar) | |
self.statusbar = QtWidgets.QStatusBar(MainWindow) | |
self.statusbar.setObjectName("statusbar") | |
MainWindow.setStatusBar(self.statusbar) | |
self.retranslateUi(MainWindow) | |
QtCore.QMetaObject.connectSlotsByName(MainWindow) | |
def openFile(self): | |
global img_path | |
get_filename_path, ok = QFileDialog.getOpenFileName() | |
if ok: | |
img_path=str(get_filename_path) | |
self.pushButton.setStyleSheet("QPushButton{border-image: url(%s)}"%str(get_filename_path)) | |
def setimg_bg(self,color): | |
global img_path,new_path | |
if img_path != '': | |
change_bg_color(img_path,color) | |
self.pushButton.setStyleSheet("QPushButton{border-image: url(%s)}"%str(new_path)) | |
def retranslateUi(self, MainWindow): | |
_translate = QtCore.QCoreApplication.translate | |
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) | |
self.pushButton.setText(_translate("MainWindow", "")) | |
self.pushButton_.setText(_translate("MainWindow", "蓝色")) | |
self.pushButton_.setText(_translate("MainWindow", "绿色")) | |
self.pushButton_.setText(_translate("MainWindow", "红色")) | |
self.pushButton_.setText(_translate("MainWindow", "白色")) | |
if __name__ == '__main__': | |
global img_path,new_path | |
img_path='' | |
app = QApplication(sys.argv) | |
MainWindow = QMainWindow() | |
ui = Ui_MainWindow() | |
ui.setupUi(MainWindow) | |
MainWindow.show() | |
sys.exit(app.exec_()) |
小结:在网络上下载不同底色的图片实验了几十次,发现白底穿白色衣服时直接将身体也被更换的底色覆盖了,所以至始至终都是超级简陋的换底,还是removebg这些经过学习的好,连发丝间都能更换,看起来比较细腻顺滑,不过在此过程中也学到了一些图片处理的知识,opencv默认是BGR的,而有些库是RGB的,所以在判断底色的时候一开始我是使用hsv,发现行不通,后面只好使用BGR提取色块来判断。