本文的代码的功能是:可以对图片文件、视频批量变换成动漫、卡通的风格,共有5种风格可以选择,使用了人工智能的算法。
本文与前几篇博文关联性较强,请事先阅读前几篇。 对此文感兴趣的可以加微深入探讨:herbert156
可运行的试用版本下载:https://pan.baidu.com/s/1QoayHKmjbFi46D2JHx9Wzw 提取码: sji5
如果提示过期,可以向博主索要新的SN文件。
一、主要功能:
以下的Python代码的功能:批量选择视频、批量选择图片、,主要包括:
1、对图片、视频进行风格变换,转换成动漫、卡通等风格,并输出变换后的文件;
2、可以批量处理,在选择文件的对话框里可以选择多个文件,进行批量操作;
3、如果电脑有GPU,则会自动选择GPU处理,加快处理速度;
4、风格一共有5种,分别是:通用日漫风格、3D立体风格、素描黑白风格、手绘彩色风格、>艺术范风格
5、信息统计里面可以实时显示处理的各种统计信息;
6、视频处理完毕后自动进行音频的处理与合成。
二、主要代码:
UI的Python代码:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'Cartoon_UI.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ai_cartoon(object):
def setupUi(self, ai_cartoon):
ai_cartoon.setObjectName("ai_cartoon")
ai_cartoon.setEnabled(True)
ai_cartoon.resize(912, 947)
font = QtGui.QFont()
font.setFamily("宋体")
font.setPointSize(12)
ai_cartoon.setFont(font)
ai_cartoon.setMouseTracking(False)
self.layoutWidget = QtWidgets.QWidget(ai_cartoon)
self.layoutWidget.setGeometry(QtCore.QRect(360, 880, 531, 41))
self.layoutWidget.setObjectName("layoutWidget")
self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.layoutWidget)
self.horizontalLayout_5.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
self.startButton = QtWidgets.QPushButton(self.layoutWidget)
font = QtGui.QFont()
font.setFamily("宋体")
font.setPointSize(12)
self.startButton.setFont(font)
self.startButton.setObjectName("startButton")
self.horizontalLayout_5.addWidget(self.startButton)
self.stopButton = QtWidgets.QPushButton(self.layoutWidget)
font = QtGui.QFont()
font.setFamily("宋体")
font.setPointSize(12)
self.stopButton.setFont(font)
self.stopButton.setObjectName("stopButton")
self.horizontalLayout_5.addWidget(self.stopButton)
spacerItem = QtWidgets.QSpacerItem(60, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout_5.addItem(spacerItem)
self.helpButton = QtWidgets.QPushButton(self.layoutWidget)
font = QtGui.QFont()
font.setFamily("宋体")
font.setPointSize(12)
self.helpButton.setFont(font)
self.helpButton.setObjectName("helpButton")
self.horizontalLayout_5.addWidget(self.helpButton)
self.quitButton = QtWidgets.QPushButton(self.layoutWidget)
font = QtGui.QFont()
font.setFamily("宋体")
font.setPointSize(12)
self.quitButton.setFont(font)
self.quitButton.setObjectName("quitButton")
self.horizontalLayout_5.addWidget(self.quitButton)
self.groupBox_2 = QtWidgets.QGroupBox(ai_cartoon)
self.groupBox_2.setGeometry(QtCore.QRect(10, 250, 881, 281))
self.groupBox_2.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
self.groupBox_2.setAlignment(QtCore.Qt.AlignCenter)
self.groupBox_2.setObjectName("groupBox_2")
self.my_label1 = QtWidgets.QLabel(self.groupBox_2)
self.my_label1.setGeometry(QtCore.QRect(12, 30, 427, 240))
self.my_label1.setObjectName("my_label1")
self.my_label2 = QtWidgets.QLabel(self.groupBox_2)
self.my_label2.setGeometry(QtCore.QRect(443, 30, 427, 240))
self.my_label2.setObjectName("my_label2")
self.groupBox_3 = QtWidgets.QGroupBox(ai_cartoon)
self.groupBox_3.setGeometry(QtCore.QRect(10, 10, 881, 221))
self.groupBox_3.setLayoutDirection(QtCore.Qt.LeftToRight)
self.groupBox_3.setAlignment(QtCore.Qt.AlignCenter)
self.groupBox_3.setObjectName("groupBox_3")
self.label = QtWidgets.QLabel(self.groupBox_3)
self.label.setGeometry(QtCore.QRect(50, 198, 81, 18))
self.label.setObjectName("label")
self.label_2 = QtWidgets.QLabel(self.groupBox_3)
self.label_2.setGeometry(QtCore.QRect(190, 198, 81, 18))
self.label_2.setObjectName("label_2")
self.label_3 = QtWidgets.QLabel(self.groupBox_3)
self.label_3.setGeometry(QtCore.QRect(340, 198, 81, 18))
self.label_3.setObjectName("label_3")
self.label_4 = QtWidgets.QLabel(self.groupBox_3)
self.label_4.setGeometry(QtCore.QRect(480, 198, 81, 18))
self.label_4.setObjectName("label_4")
self.label_5 = QtWidgets.QLabel(self.groupBox_3)
self.label_5.setGeometry(QtCore.QRect(620, 198, 81, 18))
self.label_5.setObjectName("label_5")
self.label_6 = QtWidgets.QLabel(self.groupBox_3)
self.label_6.setGeometry(QtCore.QRect(770, 198, 81, 18))
self.label_6.setObjectName("label_6")
self.groupBox_4 = QtWidgets.QGroupBox(ai_cartoon)
self.groupBox_4.setGeometry(QtCore.QRect(10, 550, 881, 111))
self.groupBox_4.setAlignment(QtCore.Qt.AlignCenter)
self.groupBox_4.setObjectName("groupBox_4")
self.filesButton = QtWidgets.QPushButton(self.groupBox_4)
self.filesButton.setGeometry(QtCore.QRect(20, 30, 78, 24))
font = QtGui.QFont()
font.setFamily("宋体")
font.setPointSize(12)
self.filesButton.setFont(font)
self.filesButton.setObjectName("filesButton")
self.outButton = QtWidgets.QPushButton(self.groupBox_4)
self.outButton.setGeometry(QtCore.QRect(20, 70, 78, 24))
font = QtGui.QFont()
font.setFamily("宋体")
font.setPointSize(12)
self.outButton.setFont(font)
self.outButton.setObjectName("outButton")
self.txt1 = QtWidgets.QLabel(self.groupBox_4)
self.txt1.setGeometry(QtCore.QRect(110, 32, 771, 20))
self.txt1.setObjectName("txt1")
self.txt2 = QtWidgets.QLabel(self.groupBox_4)
self.txt2.setGeometry(QtCore.QRect(110, 72, 771, 20))
self.txt2.setObjectName("txt2")
self.groupBox_5 = QtWidgets.QGroupBox(ai_cartoon)
self.groupBox_5.setGeometry(QtCore.QRect(10, 680, 881, 81))
self.groupBox_5.setAlignment(QtCore.Qt.AlignCenter)
self.groupBox_5.setObjectName("groupBox_5")
self.txt11 = QtWidgets.QLabel(self.groupBox_5)
self.txt11.setGeometry(QtCore.QRect(20, 20, 861, 16))
self.txt11.setObjectName("txt11")
self.txt12 = QtWidgets.QLabel(self.groupBox_5)
self.txt12.setGeometry(QtCore.QRect(20, 50, 861, 21))
self.txt12.setObjectName("txt12")
self.groupBox_6 = QtWidgets.QGroupBox(ai_cartoon)
self.groupBox_6.setGeometry(QtCore.QRect(10, 780, 881, 71))
self.groupBox_6.setAlignment(QtCore.Qt.AlignCenter)
self.groupBox_6.setObjectName("groupBox_6")
self.checkBox_1 = QtWidgets.QCheckBox(self.groupBox_6)
self.checkBox_1.setGeometry(QtCore.QRect(20, 30, 141, 16))
self.checkBox_1.setObjectName("checkBox_1")
self.checkBox_2 = QtWidgets.QCheckBox(self.groupBox_6)
self.checkBox_2.setGeometry(QtCore.QRect(210, 30, 141, 16))
self.checkBox_2.setObjectName("checkBox_2")
self.checkBox_3 = QtWidgets.QCheckBox(self.groupBox_6)
self.checkBox_3.setGeometry(QtCore.QRect(370, 30, 141, 16))
self.checkBox_3.setObjectName("checkBox_3")
self.checkBox_4 = QtWidgets.QCheckBox(self.groupBox_6)
self.checkBox_4.setGeometry(QtCore.QRect(550, 30, 141, 16))
self.checkBox_4.setObjectName("checkBox_4")
self.checkBox_5 = QtWidgets.QCheckBox(self.groupBox_6)
self.checkBox_5.setGeometry(QtCore.QRect(730, 30, 101, 16))
self.checkBox_5.setObjectName("checkBox_5")
self.sample_lbl = QtWidgets.QLabel(ai_cartoon)
self.sample_lbl.setGeometry(QtCore.QRect(26, 40, 851, 161))
self.sample_lbl.setText("")
self.sample_lbl.setObjectName("sample_lbl")
self.retranslateUi(ai_cartoon)
QtCore.QMetaObject.connectSlotsByName(ai_cartoon)
def retranslateUi(self, ai_cartoon):
_translate = QtCore.QCoreApplication.translate
ai_cartoon.setWindowTitle(_translate("ai_cartoon", "卡通、漫画风格变换工具"))
self.startButton.setText(_translate("ai_cartoon", "开始处理"))
self.stopButton.setText(_translate("ai_cartoon", "停止处理"))
self.helpButton.setText(_translate("ai_cartoon", "帮助"))
self.quitButton.setText(_translate("ai_cartoon", "退出"))
self.groupBox_2.setTitle(_translate("ai_cartoon", "预览窗口"))
self.my_label1.setText(_translate("ai_cartoon", "原图"))
self.my_label2.setText(_translate("ai_cartoon", "卡通"))
self.groupBox_3.setTitle(_translate("ai_cartoon", "变换样例"))
self.label.setText(_translate("ai_cartoon", "原始图片"))
self.label_2.setText(_translate("ai_cartoon", "日漫风格"))
self.label_3.setText(_translate("ai_cartoon", "3D立体"))
self.label_4.setText(_translate("ai_cartoon", "素描黑白"))
self.label_5.setText(_translate("ai_cartoon", "手绘彩色"))
self.label_6.setText(_translate("ai_cartoon", "艺术范"))
self.groupBox_4.setTitle(_translate("ai_cartoon", "文件设置"))
self.filesButton.setText(_translate("ai_cartoon", "选择文件"))
self.outButton.setText(_translate("ai_cartoon", "输出目录"))
self.txt1.setText(_translate("ai_cartoon", "请选择图像文件[Ctrl+A全选、Ctrl/Shift+鼠标可多选]......"))
self.txt2.setText(_translate("ai_cartoon", "输出目录"))
self.groupBox_5.setTitle(_translate("ai_cartoon", "信息统计"))
self.txt11.setText(_translate("ai_cartoon", "【图像信息】"))
self.txt12.setText(_translate("ai_cartoon", "【运行信息】"))
self.groupBox_6.setTitle(_translate("ai_cartoon", "风格选择"))
self.checkBox_1.setText(_translate("ai_cartoon", "1->日漫风格"))
self.checkBox_2.setText(_translate("ai_cartoon", "2->3D立体"))
self.checkBox_3.setText(_translate("ai_cartoon", "3->素描黑白"))
self.checkBox_4.setText(_translate("ai_cartoon", "4->手绘彩色"))
self.checkBox_5.setText(_translate("ai_cartoon", "5->艺术范"))
主处理代码:
def __init__(self):
super(MainWin, self).__init__()
self.setupUi(self)
global hwnd, run_flag
self.createLayout()
self.setWindowFlags(Qt.WindowMinimizeButtonHint)
self.show(); run_flag = 1
def CV2toPIL(self, img): # cv2转PIL
return Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGRA2RGBA))
def PILtoCV2(self, img): # PIL转cv2
return cv2.cvtColor(np.array(img), cv2.COLOR_RGBA2BGRA)
def two_pic_combine_PIL(self, back_img, fore_img): #2个图片合并
back_img = self.CV2toPIL(back_img); fore_img = self.CV2toPIL(fore_img); r,g,b,alpha = fore_img.split()
return cv2.cvtColor(self.PILtoCV2(Image.composite(fore_img, back_img, alpha)), cv2.COLOR_BGRA2BGR)
def ShowCarton(self, result, img_path, style): # 卡通转换
jpg_name = out_dir + '/' + os.path.splitext(os.path.split(img_path)[1])[0] + '_'+style+'.jpg'
cv2.imencode('.jpg', result)[1].tofile(jpg_name)
size_x = result.shape[1] # 宽度
size_y = result.shape[0] # 高度
if size_x / size_y > 1.7778: fx = 427 / size_x; fy = fx # 计算16:9的比例,以便缩放不变形
else: fx = 240 / size_y; fy = fx
self.my_label2.setPixmap(self.CvMatToQImage(cv2.resize(result, (0, 0), fx=fx, fy=fy)))
cv2.waitKey(1)
# cv2.imshow('Test', result1.astype(np.uint8)); cv2.waitKey(0)
def image_change_background(self, imagefile):
global iii, stop_flag, t0
try:
img1= cv2.imdecode(np.fromfile(imagefile, dtype=np.uint8), -1)
if img1.shape[2] == 4: img1 = cv2.cvtColor(img1, cv2.COLOR_BGRA2BGR)
except:
self.show_error('读取图片文件【'+imagefile+'】时,出现错误!\n\n原因:目录/文件名不能包含中文...'); return
cv2.waitKey(1)
if img1 is None: self.show_error('读取图片文件【'+imagefile+'】时,出现错误!\n\n原因:目录/文件名不能包含中文...'); return
size_x = img1.shape[1] # 宽度
size_y = img1.shape[0] # 高度
imageinfo = '【图片信息】 文件总数:%d | 正在处理(%d/%d):'%(filesnums,iii,filesnums) + os.path.split(imagefile)[1]+\
' | 图像分辨率:%dx%d '%(size_x,size_y)
self.txt11.setText(imageinfo)
t1 = time.time()
if size_x / size_y > 1.7778: fx = 427 / size_x; fy = fx # 计算16:9的比例,以便缩放不变形
else: fx = 240 / size_y; fy = fx
if stop_flag:
self.txt11.setText('【图片信息】 文件总s数:%d个 | 处理完成:%d个' % (filesnums, iii))
self.txt12.setText('【运行信息】 用户终止了正在运行的程序......')
return
self.my_label1.setPixmap(self.CvMatToQImage(cv2.resize(img1, (0, 0), fx=fx, fy=fy)))
if not DEBUG_FLAG: self.RunCarton(imagefile)
else: pass #img3 = img1
cv2.waitKey(1); t2 = time.time()
runinfo = '【运行信息】 当前图片处理耗时:%.3f秒 | 总处理耗时:%.1f秒 | 处理进度:%.1f%%'%((t2-t1),(t2-t0),100*(iii/filesnums))
self.txt12.setText(runinfo); cv2.waitKey(1)
self.txt12.setText('【运行信息】 处理完毕!总消耗时间:%d秒'%(t2-t0))
self.txt11.setText('【图片信息】 文件总数:%d个 | 处理完成:%d个'%(filesnums,iii))
def CvMatToQImage(self, ptr): # Converts an opencv MAT format into a QImage
ptr = cv2.cvtColor(ptr, cv2.COLOR_BGRA2RGBA) # 颜色格式转换
QtImg = QtGui.QImage(ptr.data, ptr.shape[1], ptr.shape[0], QtGui.QImage.Format_RGBA8888)
return QtGui.QPixmap.fromImage(QtImg)
# def show_error(self,str):
# r_button = QMessageBox.question(self, my_title,'\n\n'+str+'\n\n', QMessageBox.Ok)
def show_error(self, str):
infoBox = QMessageBox()
infoBox.setIcon(QMessageBox.Information)
infoBox.setText(str)
infoBox.setStandardButtons(QMessageBox.Ok)
infoBox.button(QMessageBox.Ok).animateClick(30000) # 10秒自动关闭
infoBox.exec_()
def set_False_Btn(self):
self.filesButton.setEnabled(False); self.outButton.setEnabled(False)
self.startButton.setEnabled(False); self.stopButton.setEnabled(True)
self.quitButton.setEnabled(False)
def set_True_Btn(self):
self.filesButton.setEnabled(True); self.outButton.setEnabled(True)
self.startButton.setEnabled(True); self.stopButton.setEnabled(False)
self.quitButton.setEnabled(True)
def startrun(self):
global iii,stop_flag,t0
iii = 0; stop_flag = False
self.txt12.setText('【运行信息】 正在初始化AI模型......');cv2.waitKey(1)
t0 = time.time()
if files == []: self.show_error('请选择需要变换的图像文件!'); return
if not os.path.exists(out_dir): self.show_error('输出目录不存在,请重新选择!'); return
self.set_False_Btn()
for file in files:
iii += 1
if stop_flag: break
self.image_change_background(file)
self.set_True_Btn()
def stoprun(self):
global stop_flag
r_button = QMessageBox.question(self, my_title,
"\n\n 确定要停止图片变换吗?\n\n", QMessageBox.Yes | QMessageBox.No)
if r_button == QMessageBox.Yes: stop_flag = True
def helpWin(self):
str="\n\n\n1、【选择文件】选择需要转换风格的图像文件(可多选);\n2、【输出目录】变换后的文件目录,文件名:源文件_1.jpg;\n"+\
"3、如没有Nvidia系列GPU,AI算法自动选择CPU处理;\n4、变换的模型有多种,可在多选框选择;\n\n\n"+\
" 本软件著作权归属:xxx 网址:www.xxx.com\n\n"
QMessageBox.question(self, my_title, str, QMessageBox.Ok)
def quitWin(self):
r_button = QMessageBox.question(self, my_title,
"\n\n退出将终止变换进程...... \n\n确认退出吗?\n\n", QMessageBox.Yes | QMessageBox.No)
if r_button == QMessageBox.Yes: sys.exit()
def filesButton_fuc(self):
global files,filesnums
files, ok1 = QFileDialog.getOpenFileNames(self,'请选择图像文件[全选:Ctrl+A、多选:Ctrl/Shift+鼠标]',
input_path,"*.jpg;;*.png")
filesnums = len(files)
if files!=[]:
txt='目录:'+os.path.split(files[0])[0]+' | 已选文件:'+str(filesnums)+'个 | 文件名:'
for file in files: txt=txt+ os.path.split(file)[1]+'; '
self.txt1.setText(txt)
else: self.txt1.setText('请选择图像文件[全选:Ctrl+A、多选:Ctrl/Shift+鼠标]......')
def outButton_fuc(self):
global out_dir
out_dir = QFileDialog.getExistingDirectory(self,'选择转换后的输出文件夹', work_path)
if out_dir == '': self.txt2.setText('请选择图片变换后的文件保存目录......')
else: self.txt2.setText(out_dir)
def box_choose1(self):
if self.checkBox_1.isChecked(): Style_flag[0] = True
else:Style_flag[0] = False
def box_choose2(self):
if self.checkBox_2.isChecked(): Style_flag[1] = True
else:Style_flag[1] = False
def box_choose3(self):
if self.checkBox_3.isChecked(): Style_flag[2] = True
else:Style_flag[2] = False
def box_choose4(self):
if self.checkBox_4.isChecked(): Style_flag[3] = True
else:Style_flag[3] = False
def box_choose5(self):
if self.checkBox_5.isChecked(): Style_flag[4] = True
else:Style_flag[4] = False
def createLayout(self):
self.my_label1.setPixmap(self.CvMatToQImage(img_start))
self.my_label2.setPixmap(self.CvMatToQImage(img_start))
self.my_label1.setAlignment(Qt.AlignCenter); self.my_label2.setAlignment(Qt.AlignCenter)
self.sample_lbl.setPixmap(QPixmap("sample.jpg"))
self.my_label1.setFixedSize(427, 240); self.my_label2.setFixedSize(427, 240)
self.my_label1.setAlignment(Qt.AlignCenter); self.my_label2.setAlignment(Qt.AlignCenter)
self.my_label1.setToolTip("本区域,显示的是原始图片缩略图...")
self.my_label2.setToolTip("本区域,显示的是变换后的缩略图...")
self.sample_lbl.setToolTip("本区域,显示的是各种风格的样例...")
self.checkBox_1.setChecked(True)
self.checkBox_2.setChecked(True)
self.checkBox_3.setChecked(True)
self.checkBox_4.setChecked(True)
self.checkBox_5.setChecked(True)
self.checkBox_1.stateChanged.connect(self.box_choose1)
self.checkBox_2.stateChanged.connect(self.box_choose2)
self.checkBox_3.stateChanged.connect(self.box_choose3)
self.checkBox_4.stateChanged.connect(self.box_choose4)
self.checkBox_5.stateChanged.connect(self.box_choose5)
self.filesButton.setToolTip("选择即将被变换的的图片文件,可单选、多选...")
self.outButton.setToolTip("选择输出文件目录,变换后的文件将存在此目录...")
self.txt2.setText(out_dir)
self.filesButton.clicked.connect(self.filesButton_fuc)
self.outButton.clicked.connect(self.outButton_fuc)
self.stopButton.setEnabled(False)
self.startButton.clicked.connect(self.startrun)
self.stopButton.clicked.connect(self.stoprun)
self.helpButton.clicked.connect(self.helpWin)
self.quitButton.clicked.connect(self.quitWin)