Python 实现有UI界面的图像处理小工具 PIL CV2 NUMPY

1 篇文章 0 订阅


前言

数字媒体作业需要使用任意语言编写一个图像处理小工具,并且处理过程尽量不使用库函数提供的方法,一开始使用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没有改

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值