文章目录
前言
数字媒体作业需要使用任意语言编写一个图像处理小工具,并且处理过程尽量不使用库函数提供的方法,一开始使用Python就是为了更方便使用库提供的方法QAQ环境 WIN10 Python V3.7.9
使用到的包 tkiner PIL cv2 numpy matplotlib pyplot
Ⅰ、窗体创建
1> 使用 tkinter 构建一个基本窗体
####################### 初始化GUI窗体 #######################
win = tkinter.Tk()
win.title("Hello Test")
win.geometry('1000x800')
####### 菜单栏 #######
menubar = tkinter.Menu(win)
filemenu = tkinter.Menu(menubar, tearoff=False)
filemenu.add_command(label='打开 ', command=open_file)
filemenu.add_command(label='保存 ', command=save_file)
image01 = tkinter.Menu(menubar, tearoff=False)
image01.add_command(label='灰度图 ', command=grayscale_Image)
image01.add_command(label='负片 ', command=negative_Film)
image01.add_command(label='二值化 ', command=image_binaryzation)
image01.add_command(label='提高对比度 ', command=image_enhancement)
image01.add_command(label='图像模糊 ', command=image_blur)
image01.add_separator()
image01.add_command(label='恢复原图 ', command=restore_Original)
menubar.add_cascade(label='文件', menu=filemenu)
menubar.add_cascade(label='图像', menu=image01)
win.config(menu=menubar)
####### 框 #######
frm = tkinter.Frame(win)
frm.pack()
frm_top1 = tkinter.Frame(frm, width=1000, height='5', bg='yellow')
frm_top2 = tkinter.Frame(frm, width=1000, height='5', bg='yellow')
frm_top3 = tkinter.Frame(frm, width=1000, height='5', bg='yellow')
frm_l = tkinter.Frame(frm, width="1920", height='1080', bg='red')
frm_r = tkinter.Frame(frm)
x1 = IntVar()
x2 = IntVar()
x3 = IntVar()
rch_b = tkinter.Checkbutton(frm_top1, text = "红色通道", variable = x1, \
onvalue = 1, offvalue = 0, width = 20, command=channel)
gch_b = tkinter.Checkbutton(frm_top1, text = "绿色通道", variable = x2, \
onvalue = 1, offvalue = 0, width = 20, command=channel)
bch_b = tkinter.Checkbutton(frm_top1, text = "蓝色通道", variable = x3, \
onvalue = 1, offvalue = 0, width = 20, command=channel)
rch_b.pack(side='left')
gch_b.pack(side='left')
bch_b.pack(side='left')
t01 = tkinter.Label(frm_top1, text="高比例")
E1 = tkinter.Entry(frm_top1, bd =5, width="5")
t02 = tkinter.Label(frm_top1, text="宽比例")
E2 = tkinter.Entry(frm_top1, bd =5, width="5")
B1 = tkinter.Button(frm_top1, text ="缩小", command = img_narrow)
t01.pack(side="left")
E1.pack(side="left")
t02.pack(side="left")
E2.pack(side="left")
B1.pack(side="left")
t03 = tkinter.Label(frm_top1, text="高比例")
E3 = tkinter.Entry(frm_top1, bd =5, width="5")
t04 = tkinter.Label(frm_top1, text="宽比例")
E4 = tkinter.Entry(frm_top1, bd =5, width="5")
B2 = tkinter.Button(frm_top1, text ="放大", command = img_enlarge)
t03.pack(side="left")
E3.pack(side="left")
t04.pack(side="left")
E4.pack(side="left")
B2.pack(side="left")
cv = tkinter.Canvas(frm_l, height=1920, width=1080)
# frame=tkinter.Frame(cv) #把frame放在canvas里
# frame.place(width=180, height=180) #frame的长宽,和canvas差不多的
# vbar=tkinter.Scrollbar(cv,orient=VERTICAL)
# vbar.place(x = 1000-20,width=20,height=800-100)
# vbar.configure(command=cv.yview)
# hbar=tkinter.Scrollbar(cv,orient=HORIZONTAL)#水平滚动条
# hbar.place(x =0,y=800-100,width=1000,height=20)
# hbar.configure(command=cv.xview)
cv.config(width=1920,height=1080)
# cv.config(xscrollcommand=hbar.set,yscrollcommand=vbar.set)
cv.pack()
# hbar.pack(side=BOTTOM)
# vbar.pack(side=RIGHT)
try:
# file_path = filedialog.askopenfilename(title=u'选择文件')
# im1 = Image.open(file_path) # 打开图片
# im2 = ImageTk.PhotoImage(im1) # 用PIL模块的PhotoImage打开
# imx = im1
# open_file()
pass
except:
pass
cv.create_image(10,10,image=im2,anchor="nw")
# img_cv = cv.create_image(500,500,image=photo, anchor="nw")
frm_top1.pack(side='top')
frm_top2.pack(side='top')
frm_top3.pack(side='top')
frm_l.pack(side='left')
frm_r.pack(side='right')
####### LOOP #######
win.mainloop()
Ⅱ、文件处理方法 打开和保存
1> 图像的打开
# 打开文件 获取文件路径 写入画板
def open_file():
global im1
global im2
global imx
global file_path
global cvimg
global imarray
file_pathX = filedialog.askopenfilename(title=u'选择文件')
im1 = Image.open(file_pathX)
im1.save('Source.png')
cvimg = cv2.imread(file_path)
cv2.imwrite('Source.png', cvimg)
im1 = Image.open(file_path) # 打开图片
imarray = np.array(im1)
im2 = ImageTk.PhotoImage(im1) # 用PIL模块的PhotoImage打开
cv.create_image(10,10,image=im2,anchor="nw")
imx = im1
im1.save(buffer_path)
restore_Original()
# cv.itemconfigure(img_cv, image=photo1)
# frm_l.update()
# print(img_cv)
# frm_top.config(width=win.winfo_width(),height='50') 设置窗口大小
pass
2> 图像的保存
保存方法是最后写的在之前声明了一些全局变量
def save_file():
global im2
save_path=tkinter.filedialog.asksaveasfilename(title='保存文件',defaultextension=".png")
# im2.show()
im2._PhotoImage__photo.write(save_path)
# x.save(save_path)
pass
Ⅲ、图像处理函数
1> 灰度图
def grayscale_Image():
global im2
global im1
global imx
imageWidth = imx.width
imageHeight = imx.height
# for x in range(imageWidth):
# for y in range(imageHeight):
# r,g,b=imx.getpixel((x,y))
# # print(imx.getpixel((x,y)))
# imx.putpixel((x,y),(r*1+g*2+b*1)>>2)
imx2 = imx.convert(mode='L')
im2 = ImageTk.PhotoImage(imx2)
cv.create_image(10,10,image=im2,anchor="nw")
imx2.save(buffer_path)
pass
2> 负片效果
def negative_Film():
global im2
global im1
global cvimg
# global imx
imx.convert(mode='RGB')
imageWidth = imx.width
imageHeight = imx.height
b,g,r = cv2.split(cvimg)
b = 255 - b
g = 255 - g
r = 255 - r
cvimg[:,:,0] = b
cvimg[:,:,1] = g
cvimg[:,:,2] = r
# for x in range(imageWidth):
# for y in range(imageHeight):
# r,g,b,e=imx.getpixel((x,y))
# imx.putpixel((x,y),(255-r,255-g,255-b))
image = Image.fromarray(cv2.cvtColor(cvimg,cv2.COLOR_BGR2RGB))
im2 = ImageTk.PhotoImage(image)
cv.create_image(10,10,image=im2,anchor="nw")
imx.save(buffer_path)
pass
3> 图片缩小
# 图片缩放
def img_narrow():
global cvimg
global im2
global imarray
global imx
imageWidth = imx.width
imageHeight = imx.height
# dsize=(0.5*width,0.5*height)
# size = (int(E1.get()), int(E2.get()))
# cvimg = cv2.resize(cvimg, size)
height = np.double(E1.get())
width = np.double(E2.get())
output_h = round(imageHeight * height)
output_w = round(imageWidth * width)
new_arr = np.zeros((output_h, output_w, 3), dtype = "uint8")
for i in range(output_h):
for j in range(output_w):
# imx.putpixel((i,j),(imarray[round((i+1)/0.6-1), round((j+1)/0.6-1),0], imarray[round((i+1)/0.6-1), round((j+1)/0.6-1),1], imarray[round((i+1)/0.6-1), round((j+1)/0.6-1),2]))
# print(type(imarray[round((i+1)/0.6-1), round((j+1)/0.6-1), 0]))
# imarray[round((i+1)/0.6-1), round((j+1)/0.6-1)][1], \
# imarray[round((i+1)/0.6-1), round((j+1)/0.6-1)][2])
new_arr[i, j] = imarray[round((i+1)/height-1), round((j+1)/width-1)]
new_im = Image.fromarray(new_arr)
image = Image.fromarray(cv2.cvtColor(new_arr,cv2.COLOR_BGR2RGB))
im2 = ImageTk.PhotoImage(image)
cv.create_image(10,10,image=im2,anchor="nw")
imx.save(buffer_path)
pass
4> 图片放大
# 图片放大 最近点插值
def img_enlarge():
global cvimg
global im2
global imarray
global imx
imageWidth = imx.width
imageHeight = imx.height
height = np.double(E3.get())
width = np.double(E4.get())
output_h = round(imageHeight * height)
output_w = round(imageWidth * width)
new_arr = np.zeros((output_h, output_w, 3), dtype = "uint8")
for i in range(output_h):
for j in range(output_w):
x = round((i+1)/height-1)
y = round((j+1)/width-1)
new_arr[i, j] = imarray[x, y]
new_im = Image.fromarray(new_arr)
image = Image.fromarray(cv2.cvtColor(new_arr,cv2.COLOR_BGR2RGB))
im2 = ImageTk.PhotoImage(image)
cv.create_image(10,10,image=im2,anchor="nw")
imx.save(buffer_path)
pass
5> 增强对比度
# 对比度增强 线性变换
def image_enhancement():
global imarray
global im2
global cvimg
a=1.5
b=0
y = np.float64(a)*cvimg+b
y[y>255]=255
y = np.round(y)
img_bright= y.astype(np.uint8)
image = Image.fromarray(cv2.cvtColor(img_bright,cv2.COLOR_BGR2RGB))
im2 = ImageTk.PhotoImage(image)
cv.create_image(10,10,image=im2,anchor="nw")
pass
6> 图像模糊 高斯模糊
def clamp(pv):
if pv > 255 :
return 255
if pv < 0:
return 0
else :
return pv
# 图像模糊 高斯模糊
def image_blur():
global im2
global cvimg
h,w,c = cvimg.shape
for row in range(h):
for col in range(w):
gn = np.random.normal(0,30,4)
b = cvimg[row, col, 0]
g = cvimg[row, col, 1]
r = cvimg[row, col, 2]
cvimg[row, col, 0] = clamp(b + gn[0])
cvimg[row, col, 1] = clamp(g + gn[1])
cvimg[row, col, 2] = clamp(r + gn[2])
image = Image.fromarray(cv2.cvtColor(cvimg,cv2.COLOR_BGR2RGB))
im2 = ImageTk.PhotoImage(image)
cv.create_image(10,10,image=im2,anchor="nw")
pass
7> 图像二值化
# 数值是我写死在程序里面的就是下面的x
def image_binaryzation():
global im2
global cvimg
x = 100
gray = cv2.cvtColor(cvimg, cv2.COLOR_BGR2GRAY)
h, w = gray.shape[:2]
for i in range(h):
for j in range(w):
if gray[i,j] > x:
gray[i,j] = 255
else :
gray[i,j] = 0
image = Image.fromarray(cv2.cvtColor(gray,cv2.COLOR_BGR2RGB))
im2 = ImageTk.PhotoImage(image)
cv.create_image(10,10,image=im2,anchor="nw")
pass
8> RGB通道
def channel():
global imx
global im2
global buffer_path
global x1,x2,x3
imx.convert(mode='RGB')
imageWidth = imx.width
imageHeight = imx.height
imlocal = Image.open(buffer_path)
# print(x1.get())
# print(x2.get())
# print(x3.get())
for x in range(imageWidth):
for y in range(imageHeight):
r,g,b =imlocal.getpixel((x,y))
# print(r)
if x1.get() != 1:
r=0
if x2.get() != 1:
g=0
if x3.get() != 1:
b=0
# if x1.get() == 1 and x2.get() == 1 and x3.get() == 1:
# # imlocal.putpixel((x,y),(r,g,b))
# imx.convert(mode='RGB')
# elif x1.get() == 1 and x2.get() == 1:
# # imlocal.putpixel((x,y),(r,g,0))
# imx.convert(mode='RG')
# elif x2.get() == 1 and x3.get() == 1:
# # imlocal.putpixel((x,y),(0,g,b))
# imx.convert(mode='GB')
# elif x1.get() == 1 and x3.get() == 1:
# # imlocal.putpixel((x,y),(r,0,b))
# imx.convert(mode='RB')
# elif x1.get() == 1:
# # imlocal.putpixel((x,y),(r,0,0))
# imx.convert(mode='R')
# elif x2.get() == 1:
# # imlocal.putpixel((x,y),(0,g,0))
# imx.convert(mode='G')
# elif x3.get() == 1:
# # imlocal.putpixel((x,y),(0,0,b))
# imx.convert(mode='B')
imlocal.putpixel((x,y),(r,g,b))
im2 = ImageTk.PhotoImage(imlocal)
cv.create_image(10,10,image=im2,anchor="nw")
pass
9>恢复原图
# 重置图片
def restore_Original():
global im1
global file_path
global im2
global imx
im1 = Image.open(file_path)
im2 = ImageTk.PhotoImage(im1)
cv.create_image(10,10,image=im2,anchor="nw")
imx = im1
imx.save(buffer_path)
x1.set(1)
x2.set(1)
x3.set(1)
pass
Ⅳ 程序下载
链接:https://pan.baidu.com/s/1I5l2qeWArMRVwi33WKAzog
提取码:XGMO
–来自百度网盘超级会员V4的分享
总结
RGB通道使用的方式在处理较大图片时候会有很长时间的卡顿 没有进行优化
有些方法在处理之后没有赋值给全局变量会有效果不能叠加显示的状态
负片效果注释掉的代码是使用对数组遍历的方式用255减去RGB像素点在处理大型图片会明显卡顿
还有很多BUG没有改