This is a simple tkinter programm based on the Open Source Project: GitHub - xinntao/Real-ESRGAN: Real-ESRGAN aims at developing Practical Algorithms for General Image/Video Restoration.
The latest version is not provided here. If you wish to obtain it, please make contact on WeChat: p1504891917. I can provide you with the executable file(.exe). However, the resources code will not be provided.
The lastest version GUI is like this:
The version provided below is quite old and filled with bugs. However, it can still function regardless. You can follow the steps below and try running the old version program.
When you enter the link:
you need to:
①download the "Portable executable files (NCNN)" one
②then make dir "Load_picture", and put a picture name "Default.jpg" into it. You can choose whatever picuture you like.
③Then, you can put my python project in the sibling folders which contains a executable procedure called "realesrgan-ncnn-vulkan.exe".
import tkinter as tk
from threading import Semaphore, Thread
from tkinter import filedialog, messagebox, Scrollbar, ttk
from subprocess import Popen, PIPE, STDOUT
from re import search
from PIL import Image, ImageTk
from os import path, remove, scandir
class GUI(object):
def __init__(self):
self.root = tk.Tk()
self.img_app = ImageApp()
self.infile_path = None
self.outfile_path = None
self.infile_path_entry = None
self.output_folder_entry = None
self.img_label1 = None
self.img_label2 = None
self.open_button1 = None
self.open_button2 = None
self.original_frame = None
self.dealt_frame = None
self.command_frame = None
self.output_info_frame = None
self.dealt_mode_combobox = None
self.module_combobox = None
self.scale_combobox = None
self.extension_combobox = None
self.output_text = None
self.set_all_element()
def set_all_element(self):
# 布置所有控件
self.set_root_win()
self.set_frame()
self.set_info_label()
self.set_open_button()
self.set_entry_and_output_text()
self.show_default_img()
self.set_combobox()
self.root.mainloop()
def set_root_win(self):
self.root.resizable(False, False)
self.root.title("超分辨率处理GUI")
self.root.geometry('1080x650+300+100')
def set_frame(self):
self.original_frame = tk.Frame(self.root, borderwidth=2, relief='solid',
highlightbackground='gray', highlightthickness=2)
self.dealt_frame = tk.Frame(self.root, borderwidth=2, relief='solid',
highlightbackground='gray', highlightthickness=2)
self.command_frame = tk.Frame(self.root, borderwidth=2, relief='solid')
self.output_info_frame = tk.Frame(self.root, borderwidth=2, relief='solid')
self.command_frame.place(x=0, y=322, height=328, width=540)
self.output_info_frame.place(x=540, y=322, height=328, width=540)
def set_info_label(self):
label1 = tk.Label(self.root, text='原图', font=('宋体', 17))
label2 = tk.Label(self.root, text='处理后图片', font=('宋体', 17))
label3 = tk.Label(self.root, text='图片处理模式:', font=('宋体', 16))
label4 = tk.Label(self.root, text='图片输入路径:', font=('宋体', 16))
label5 = tk.Label(self.root, text='图片输出路径:', font=('宋体', 16))
label6 = tk.Label(self.root, text='参数模型路径:', font=('宋体', 16))
label7 = tk.Label(self.root, text='图片放大尺寸:', font=('宋体', 16))
label8 = tk.Label(self.root, text='输出文件格式:', font=('宋体', 16))
label1.place(x=210, y=293)
label2.place(x=780, y=293)
label3.place(x=25, y=340)
label4.place(x=25, y=390)
label5.place(x=25, y=440)
label6.place(x=25, y=490)
label7.place(x=25, y=540)
label8.place(x=240, y=540)
def set_open_button(self):
self.open_button1 = tk.Button(self.root, text="预览图片", bg="wheat", font=('宋体', 13),
command=lambda: self.img_app.open_img(self.infile_path))
self.open_button2 = tk.Button(self.root, text="预览图片", bg="wheat", font=('宋体', 13),
command=lambda: self.img_app.open_img(self.outfile_path))
open_folder1 = tk.Button(self.root, text="打开文件夹", bg="wheat", font=('宋体', 13),
command=self.img_app.open_folder)
open_folder2 = tk.Button(self.root, text='选择文件夹', bg="wheat",
command=lambda: self.choose_folder(1))
open_file = tk.Button(self.root, text='打开文件', bg='wheat', font=('宋体', 12),
command=self.check_open)
execute_btn = tk.Button(self.root, text='开始图片处理', font=('宋体', 16), bg='peachpuff',
command=self.execute_entry)
self.open_button1.place(x=378, y=293, width=80)
self.open_button2.place(x=570, y=293)
open_folder1.place(x=665, y=293)
open_folder2.place(x=378, y=440, width=75)
open_file.place(x=378, y=390, height=30)
execute_btn.place(x=200, y=590)
def set_entry_and_output_text(self):
self.infile_path_entry = tk.Entry(self.root, width=30)
self.infile_path_entry.place(x=165, y=390, height=30)
self.output_folder_entry = tk.Entry(self.root, width=30)
self.output_folder_entry.place(x=165, y=440, height=30)
output_scrollbar = Scrollbar(self.root)
output_scrollbar.place(x=1060, y=325, height=320)
self.output_text = tk.Text(self.root, font=('宋体', 18))
self.output_text.place(x=542, y=323, width=518, height=323) # width=535
self.output_text.config(yscrollcommand=output_scrollbar.set)
output_scrollbar.config(command=self.output_text.yview)
def set_combobox(self):
self.dealt_mode_combobox = ttk.Combobox(self.root, values=['单张图片处理', '批量图片处理'], font=('宋体', 14))
self.dealt_mode_combobox.insert(tk.END, '单张图片处理')
self.dealt_mode_combobox.config(state='readonly')
self.module_combobox = ttk.Combobox(self.root, values=[
r"models/realesr-animevideov3-x2.bin",
r"models/realesr-animevideov3-x3.bin",
r"models/realesr-animevideov3-x4.bin",
r"models/realesrgan-x4plus.bin",
r"models/realesrgan-x4plus-anime.bin"
])
self.module_combobox.insert(tk.END, r"models/realesrgan-x4plus-anime.bin")
self.module_combobox.config(state='readonly')
self.scale_combobox = ttk.Combobox(self.root, values=['2', '3', '4'])
self.scale_combobox.insert(tk.END, '4')
self.scale_combobox.config(state='readonly')
self.extension_combobox = ttk.Combobox(self.root, values=['.jpg', '.png', '.webp'])
self.extension_combobox.insert(tk.END, '.png')
self.extension_combobox.config(state='readonly')
self.dealt_mode_combobox.place(x=165, y=340, width=160, height=30)
self.module_combobox.place(x=165, y=490, width=285, height=30)
self.scale_combobox.place(x=165, y=540, width=60, height=30)
self.extension_combobox.place(x=380, y=540, width=70, height=30)
def choose_img(self):
choose_img = filedialog.askopenfilename(title='选择图片', initialdir=self.infile_path)
if not choose_img:
return
elif not search(r'\.(jpg|png|jpeg|webp)$', choose_img, 2):
messagebox.showwarning('警告', '文件加载失败!\n只允许选择图片文件\n(png/jpg/jpeg/webp)!')
return
elif path.getsize(choose_img) > 15728640:
messagebox.showerror('错误', '图片过大(>15MB),为避免最终\n生成的图片过大,拒绝加载!!')
return
self.infile_path = choose_img
self.infile_path_entry.insert(tk.END, choose_img)
self.img_app.change_img(self.img_label1, choose_img)
def choose_folder(self, flag):
folder_selected = filedialog.askdirectory(initialdir=self.infile_path)
if not folder_selected:
return
if flag == 1:
self.img_app.folder_path = folder_selected
self.output_folder_entry.delete(0, 'end')
self.output_folder_entry.insert(0, folder_selected)
if self.dealt_mode_combobox.get() == '单张图片处理':
original_file_name = path.basename(self.infile_path)
self.outfile_path = path.join(folder_selected, f'output-{original_file_name}')
else:
self.outfile_path = folder_selected
elif flag == 2:
self.infile_path_entry.delete(0, 'end')
self.infile_path_entry.insert(0, folder_selected)
self.infile_path = folder_selected
def check_open(self):
if self.dealt_mode_combobox.get() == '单张图片处理':
self.choose_img()
else:
self.choose_folder(2)
def show_default_img(self):
original_img = Image.open("Load_picture/Default.jpg").copy()
dealt_img = Image.open("Load_picture/Default.jpg").copy()
original_img.thumbnail((540, 292), Image.LANCZOS)
dealt_img.thumbnail((540, 292), Image.LANCZOS)
photo1 = ImageTk.PhotoImage(original_img)
photo2 = ImageTk.PhotoImage(dealt_img)
self.img_label1 = tk.Label(self.original_frame, image=photo1)
self.img_label2 = tk.Label(self.dealt_frame, image=photo2)
self.img_label1.pack(fill=tk.BOTH, expand=True)
self.img_label2.pack(fill=tk.BOTH, expand=True)
self.img_label1.image = photo1
self.img_label2.image = photo2
self.original_frame.place(x=0, y=0, height=291.6, width=540)
self.dealt_frame.place(x=540, y=0, height=291.6, width=540)
def execute_entry(self):
# 传入基本参数
if self.infile_path is None or self.outfile_path is None:
messagebox.showinfo('提示', '文件输入或输出\n路径不能为空!')
return
scale = self.scale_combobox.get()
extension = self.extension_combobox.get().replace('.', '')
module = self.module_combobox.get()
# 传入大量必要参数
exe = ExecuteCommand(self.infile_path, self.outfile_path, scale, extension,
module, self.output_text, self.img_app, self.img_label1,
self.img_label2, self.open_button1, self.open_button2)
if exe.catch_exception(self.infile_path, True):
messagebox.showerror('提示', '图片解压缩后体积\n超过15MB,无法处理!')
return
exe.enter_mode(self.dealt_mode_combobox.get())
class ImageApp(object):
def __init__(self):
self.folder_path = 'Load_picture'
def open_folder(self):
# 这一步替换异常关键,我发现用'/'没法跳转到正确路径,估计和系统有关
self.folder_path = self.folder_path.replace('/', '\\')
Popen(['explorer', self.folder_path], shell=True)
@staticmethod
def open_img(img_path):
if img_path is None:
img_path = "Load_picture/Default.jpg"
Popen(['start', img_path], shell=True)
@staticmethod
def resize_image(image_path):
# 先给权限!
Image.MAX_IMAGE_PIXELS = 314572800
try:
img = Image.open(image_path)
except Image.DecompressionBombError:
messagebox.showerror('错误', '图片过大(>200MB),压缩失败!\n生成图片已销毁!')
remove(image_path)
return
w, h = img.size
img.resize((w // 2, h // 2), Image.LANCZOS)
img.save(image_path)
# 恢复原权限
Image.MAX_IMAGE_PIXELS = 89478485
@staticmethod
def change_img(img_label: tk.Label, img_path):
image = Image.open(img_path).copy()
image.thumbnail((540, 292), Image.LANCZOS)
photo = ImageTk.PhotoImage(image)
img_label.config(image=photo)
# 保持对新图片的引用
img_label.image = photo
class ExecuteCommand:
def __init__(self, infile_path, outfile_path, scale, extension, module, output_text,
img_app, input_label, output_label, open_btn1, open_btn2):
self.infile_path = infile_path
self.outfile_path = outfile_path
self.scale = scale
self.extension = extension
self.module = module
self.output_text = output_text
self.img_app = img_app
self.input_label = input_label
self.output_label = output_label
self.open_btn1 = open_btn1
self.open_btn2 = open_btn2
# 至多开启5个线程同步操作
self.semaphore = Semaphore(5)
def catch_exception(self, infile_path, twice_check=False) -> bool:
# 因为这里的异常捕捉是要反复用的,因此要更细致的判断
if path.isdir(infile_path):
return False
try:
Image.MAX_IMAGE_PIXELS = 15728640
img = Image.open(infile_path)
except Image.DecompressionBombError:
self.output_text.insert(tk.END, f'\n图片:{infile_path}解压缩后体积超过15MB, \n无法继续处理!\n')
return True
finally:
Image.MAX_IMAGE_PIXELS = 89478485
if not twice_check:
# 如果不是二次检查的话,那么就当它通过检查了
return False
w, h = img.size
img.close()
if w * h > 10485760:
return not messagebox.askokcancel('警告', '当前图片体积超过10MB,继续处理\n最终产出的照片'
'大概率效果不佳\n且体积极大!!\n确定继续处理?')
def enter_mode(self, mode: str):
if mode == '单张图片处理':
if path.isdir(self.infile_path):
messagebox.showerror('错误', '单张图片处理要求\n输入路径为图片!')
return
messagebox.showinfo('提示', '开始处理!')
# 如果是单张图片处理,处理完一张照片就会显示处理完成
self.single_img_mode(self.outfile_path, True)
elif mode == '批量图片处理':
if path.isfile(self.infile_path):
messagebox.showerror('错误', '批量图片处理要求\n输入路径为文件夹!')
return
messagebox.showinfo('提示', '开始处理!')
output_folder = self.outfile_path
self.multiple_img_mode(output_folder)
def single_img_mode(self, outfile_path, flag):
command = f'''realesrgan-ncnn-vulkan -i {self.infile_path} -o {outfile_path}
-m {self.module} -s {self.scale} -v {self.extension}'''
self.output_text.config(state='normal')
self.output_text.delete('1.0', tk.END)
Thread(target=self.stream_command_output,
args=(command, outfile_path, flag)).start()
def multiple_img_mode(self, output_folder):
file_count = sum(1 for entry in scandir(self.infile_path) if entry.is_file())
if file_count > 200:
response = messagebox.askokcancel('警告', '您要处理的照片超过200张,\n确定继续处理吗?')
if not response:
return
files = scandir(self.infile_path)
# outfile_path不能共享!!不然前面的函数还没执行完,后面的函数就着急忙慌的把路径给改了!!
flag = False
for index, file in enumerate(files, 1):
if path.isdir(file.path):
self.output_text.insert(tk.END, f'{file.name}为文件夹,已跳过。\n')
continue
elif self.catch_exception(file.path):
continue
elif index == file_count:
flag = True
self.img_app.change_img(self.input_label, file.path)
self.open_btn1.config(command=lambda: self.img_app.open_img(file.path))
outfile_path = path.join(output_folder, f'output-{file.name}')
self.open_btn2.config(command=lambda: self.img_app.open_img(outfile_path))
self.infile_path = file.path
self.single_img_mode(outfile_path, flag)
def stream_command_output(self, command, outfile_path, flag=False):
self.semaphore.acquire()
self.output_text.insert(tk.END, f'执行命令>>\n{command}\n')
process = Popen(command, stdout=PIPE, stderr=STDOUT,
shell=True, text=True)
for line in iter(process.stdout.readline, ''):
self.output_text.insert(tk.END, line)
self.output_text.see(tk.END)
if path.getsize(outfile_path) > 10485760:
self.output_text.insert(tk.END, '\n正在压缩图片......\n')
self.img_app.resize_image(outfile_path)
self.output_text.insert(tk.END, '\n图片压缩完成!\n')
self.output_text.insert(tk.END, '100.00%\n')
self.output_text.see(tk.END)
self.semaphore.release()
# 如果能赶得上加载图片的话就加载
self.img_app.change_img(self.output_label, outfile_path)
process.stdout.close()
process.wait()
if flag:
messagebox.showinfo('提示', '处理完成!')
if __name__ == '__main__':
Gui = GUI()
As you see, it's a broken program but it can still run, hhh