|
|
@ -0,0 +1,222 @@
|
|
|
|
|
|
|
|
from PIL import Image, ImageTk
|
|
|
|
|
|
|
|
from PIL import ImageFilter
|
|
|
|
|
|
|
|
import tkinter as tk # 导入 Tkinter 库
|
|
|
|
|
|
|
|
from tkinter.filedialog import askopenfilename
|
|
|
|
|
|
|
|
import tkinter.messagebox
|
|
|
|
|
|
|
|
import tkinter.ttk
|
|
|
|
|
|
|
|
import tkinter.messagebox
|
|
|
|
|
|
|
|
from PIL import ImageDraw
|
|
|
|
|
|
|
|
from PIL import ImageFont
|
|
|
|
|
|
|
|
from PIL import ImageEnhance
|
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
|
|
|
|
import cv2 as cv
|
|
|
|
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
|
|
|
from tkinter import simpledialog
|
|
|
|
|
|
|
|
import collections
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class wlw(object):
|
|
|
|
|
|
|
|
"""description of class"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 加了滤镜的拓展功能,用的ImageFilter库
|
|
|
|
|
|
|
|
def blurPic(Imf):
|
|
|
|
|
|
|
|
Im2 = Imf.filter(ImageFilter.BLUR) # 图像模糊
|
|
|
|
|
|
|
|
return Im2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def edge(Imf):
|
|
|
|
|
|
|
|
Im4 = Imf.filter(ImageFilter.EDGE_ENHANCE) # 边界增强
|
|
|
|
|
|
|
|
return Im4
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def gaussianBlur(Imf):
|
|
|
|
|
|
|
|
Im6 = Imf.filter(ImageFilter.GaussianBlur) # 高斯模糊
|
|
|
|
|
|
|
|
return Im6
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def emboss(Imf):
|
|
|
|
|
|
|
|
Im8 = Imf.filter(ImageFilter.EMBOSS) # 浮雕滤镜,
|
|
|
|
|
|
|
|
return Im8
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 以下为自己编写函数实现的功能
|
|
|
|
|
|
|
|
# 线性灰度转换
|
|
|
|
|
|
|
|
def linearization(Imf, a=1.5, c=1.5):
|
|
|
|
|
|
|
|
Im12 = np.array(Imf)
|
|
|
|
|
|
|
|
r, g, b = Im12[:, :, 0], Im12[:, :, 1], Im12[:, :, 2]
|
|
|
|
|
|
|
|
Im12 = 0.2989 * r + 0.5870 * g + 0.1140 * b
|
|
|
|
|
|
|
|
Im12 = float(a) * Im12 + float(c) # 对矩阵类型计算,a是对比度,c是亮度,由k和b传入
|
|
|
|
|
|
|
|
# 进行数据截断,大于255的值要截断为255
|
|
|
|
|
|
|
|
Im12[Im12 > 255] = 255
|
|
|
|
|
|
|
|
# 数据类型转化
|
|
|
|
|
|
|
|
Im12 = np.round(Im12)
|
|
|
|
|
|
|
|
Im12 = Im12.astype(np.uint8)
|
|
|
|
|
|
|
|
return Image.fromarray(Im12)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 非线性log灰度转换
|
|
|
|
|
|
|
|
def tologpic(Imf, c=30.0):
|
|
|
|
|
|
|
|
Im14 = np.array(Imf)
|
|
|
|
|
|
|
|
r, g, b = Im14[:, :, 0], Im14[:, :, 1], Im14[:, :, 2]
|
|
|
|
|
|
|
|
Im14 = 0.2989 * r + 0.5870 * g + 0.1140 * b
|
|
|
|
|
|
|
|
Im14 = c * np.log(1.0 + Im14) # 对数运算
|
|
|
|
|
|
|
|
Im14[Im14 > 255] = 255 # 这里应该是不用截断的
|
|
|
|
|
|
|
|
Im14 = np.uint8(Im14 + 0.5)
|
|
|
|
|
|
|
|
return Image.fromarray(Im14)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# n值灰度转换
|
|
|
|
|
|
|
|
def tonpic(Imf, n=1.5):
|
|
|
|
|
|
|
|
Im16 = np.array(Imf) # 转换矩阵
|
|
|
|
|
|
|
|
r, g, b = Im16[:, :, 0], Im16[:, :, 1], Im16[:, :, 2] # 灰度变换
|
|
|
|
|
|
|
|
Im16 = 0.2989 * r + 0.5870 * g + 0.1140 * b
|
|
|
|
|
|
|
|
Im16 = float(n) * Im16 # 对矩阵类型计算
|
|
|
|
|
|
|
|
# 进行数据截断,大于255的值要截断为255
|
|
|
|
|
|
|
|
Im16[Im16 > 255] = 255
|
|
|
|
|
|
|
|
# 数据类型转化
|
|
|
|
|
|
|
|
Im16 = np.round(Im16)
|
|
|
|
|
|
|
|
Im16 = Im16.astype(np.uint8)
|
|
|
|
|
|
|
|
return Image.fromarray(Im16)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 计算直方图
|
|
|
|
|
|
|
|
def showhist(image):
|
|
|
|
|
|
|
|
def clczhifangtu(gray):
|
|
|
|
|
|
|
|
# 计算彩色图单通道的直方图
|
|
|
|
|
|
|
|
hist_new = []
|
|
|
|
|
|
|
|
num = []
|
|
|
|
|
|
|
|
hist_result = []
|
|
|
|
|
|
|
|
hist_key = []
|
|
|
|
|
|
|
|
gray1 = list(gray.ravel()) # 将读取出来的数组转化为一维列表方便循环遍历
|
|
|
|
|
|
|
|
obj = dict(collections.Counter(gray1)) # 计算每个灰度级出现的次数
|
|
|
|
|
|
|
|
obj = sorted(obj.items(), key=lambda item: item[0])
|
|
|
|
|
|
|
|
# 初始化hist数组
|
|
|
|
|
|
|
|
for each in obj:
|
|
|
|
|
|
|
|
hist1 = []
|
|
|
|
|
|
|
|
key = list(each)[0]
|
|
|
|
|
|
|
|
each = list(each)[1]
|
|
|
|
|
|
|
|
hist_key.append(key)
|
|
|
|
|
|
|
|
hist1.append(each)
|
|
|
|
|
|
|
|
hist_new.append(hist1)
|
|
|
|
|
|
|
|
# 检查从0-255每个通道是否都有个数,没有的话添加并将值设为0
|
|
|
|
|
|
|
|
for i in range(0, 256):
|
|
|
|
|
|
|
|
if i in hist_key:
|
|
|
|
|
|
|
|
num = hist_key.index(i)
|
|
|
|
|
|
|
|
hist_result.append(hist_new[num])
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
hist_result.append([0])
|
|
|
|
|
|
|
|
# 检查循环后的列表中是不是已经包含所有的灰度级
|
|
|
|
|
|
|
|
if len(hist_result) < 256:
|
|
|
|
|
|
|
|
for i in range(0, 256 - len(hist_result)):
|
|
|
|
|
|
|
|
hist_new.append([0])
|
|
|
|
|
|
|
|
hist_result = np.array(hist_result)
|
|
|
|
|
|
|
|
return hist_result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
image = np.array(image)
|
|
|
|
|
|
|
|
r, g, b = image[:, :, 0], image[:, :, 1], image[:, :, 2]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hist_new_b = clczhifangtu(b)
|
|
|
|
|
|
|
|
hist_new_g = clczhifangtu(g)
|
|
|
|
|
|
|
|
hist_new_r = clczhifangtu(r)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 绘制直方图
|
|
|
|
|
|
|
|
plt.plot(hist_new_b, color='b')
|
|
|
|
|
|
|
|
plt.plot(hist_new_g, color='g')
|
|
|
|
|
|
|
|
plt.plot(hist_new_r, color='r')
|
|
|
|
|
|
|
|
plt.show()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 图像相加
|
|
|
|
|
|
|
|
def Add(img1, img2):
|
|
|
|
|
|
|
|
# 图像相加函数
|
|
|
|
|
|
|
|
def IMG_PLUS(img1, img2):
|
|
|
|
|
|
|
|
# 先修改img1尺寸和img2相同
|
|
|
|
|
|
|
|
img1 = cv.resize(img1, (img2.shape[1], img2.shape[0]))
|
|
|
|
|
|
|
|
# 矩阵相加
|
|
|
|
|
|
|
|
newimg = img1 * 0.5 + img2 * 0.5
|
|
|
|
|
|
|
|
newimg = newimg.astype(np.uint8)
|
|
|
|
|
|
|
|
return newimg
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
first = np.array(img1)
|
|
|
|
|
|
|
|
second = np.array(img2)
|
|
|
|
|
|
|
|
newimg = IMG_PLUS(first, second)
|
|
|
|
|
|
|
|
return ImageTk.PhotoImage(Image.fromarray(newimg))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 均值滤波
|
|
|
|
|
|
|
|
def filter1(img):
|
|
|
|
|
|
|
|
def filter(img, b=3):
|
|
|
|
|
|
|
|
padnum = (b - 1) // 2 # 填充数量
|
|
|
|
|
|
|
|
pad = ((padnum, padnum), (padnum, padnum), (0, 0)) # 填充格式
|
|
|
|
|
|
|
|
Filter = np.ones((b, b, img.shape[2]), img.dtype) # 方阵滤波器
|
|
|
|
|
|
|
|
padnumImg = np.pad(img, pad, 'constant', constant_values=(0, 0))
|
|
|
|
|
|
|
|
# 用滤波器对图像中像素依次计算取均值
|
|
|
|
|
|
|
|
for i in range(padnum, padnumImg.shape[0] - padnum):
|
|
|
|
|
|
|
|
for j in range(padnum, padnumImg.shape[1] - padnum):
|
|
|
|
|
|
|
|
padnumImg[i][j] = (Filter * padnumImg[i - padnum:i + padnum + 1, j - padnum:j + padnum + 1]).sum(
|
|
|
|
|
|
|
|
axis=0).sum(axis=0) // (b ** 2)
|
|
|
|
|
|
|
|
newimg = padnumImg[padnum:padnumImg.shape[0] - padnum, padnum:padnumImg.shape[1] - padnum] # 剪切使尺寸一样
|
|
|
|
|
|
|
|
return newimg
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
l = simpledialog.askinteger(title='滤波核size', prompt='边长L', initialvalue=3, minvalue=0, maxvalue=99)
|
|
|
|
|
|
|
|
img = filter(np.array(img), l)
|
|
|
|
|
|
|
|
return ImageTk.PhotoImage(Image.fromarray(img))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 中值滤波
|
|
|
|
|
|
|
|
def filter2(img):
|
|
|
|
|
|
|
|
# 中值滤波处理函数
|
|
|
|
|
|
|
|
def filter(img, b=3):
|
|
|
|
|
|
|
|
padnum = (b - 1) // 2 # 填充数量
|
|
|
|
|
|
|
|
pad = ((padnum, padnum), (padnum, padnum), (0, 0)) # 填充格式
|
|
|
|
|
|
|
|
padImg = np.pad(img, pad, 'constant', constant_values=(0, 0)) # 方阵滤波器
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 按通道计算中值函数
|
|
|
|
|
|
|
|
def DimensionAdd(img):
|
|
|
|
|
|
|
|
blank = np.zeros((img.shape[2]))
|
|
|
|
|
|
|
|
for i in range(img.shape[2]):
|
|
|
|
|
|
|
|
blank[i] = np.median(img[:, :, i])
|
|
|
|
|
|
|
|
return blank
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 用滤波器对图像中像素依次计算中值
|
|
|
|
|
|
|
|
for i in range(padnum, padImg.shape[0] - padnum):
|
|
|
|
|
|
|
|
for j in range(padnum, padImg.shape[1] - padnum):
|
|
|
|
|
|
|
|
padImg[i][j] = DimensionAdd(padImg[i - padnum:i + padnum + 1, j - padnum:j + padnum + 1])
|
|
|
|
|
|
|
|
newimg = padImg[padnum:padImg.shape[0] - padnum, padnum:padImg.shape[1] - padnum] # 把操作完多余的0去除,保证尺寸一样大
|
|
|
|
|
|
|
|
return newimg
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
l = simpledialog.askinteger(title='滤波核size', prompt='边长L', initialvalue=3, minvalue=0, maxvalue=99)
|
|
|
|
|
|
|
|
img = filter(np.array(img), l)
|
|
|
|
|
|
|
|
return ImageTk.PhotoImage(Image.fromarray(img))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# sobel锐化
|
|
|
|
|
|
|
|
def sharpen(img):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
img = np.array(img)
|
|
|
|
|
|
|
|
r, g, b = img[:, :, 0], img[:, :, 1], img[:, :, 2]
|
|
|
|
|
|
|
|
img = 0.2989 * r + 0.5870 * g + 0.1140 * b
|
|
|
|
|
|
|
|
# sobel算子
|
|
|
|
|
|
|
|
G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
|
|
|
|
|
|
|
|
G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
|
|
|
|
|
|
|
|
rows = np.size(img, 0)
|
|
|
|
|
|
|
|
columns = np.size(img, 1)
|
|
|
|
|
|
|
|
mag = np.zeros(img.shape)
|
|
|
|
|
|
|
|
# 分别检测水平和垂直,在计算每个pixel的时候,将水平和垂直的值作一次平方和的处理
|
|
|
|
|
|
|
|
for i in range(0, rows - 2):
|
|
|
|
|
|
|
|
for j in range(0, columns - 2):
|
|
|
|
|
|
|
|
v = sum(sum(G_x * img[i:i + 3, j:j + 3])) # vertical
|
|
|
|
|
|
|
|
h = sum(sum(G_y * img[i:i + 3, j:j + 3])) # horizon
|
|
|
|
|
|
|
|
mag[i + 1, j + 1] = np.sqrt((v ** 2) + (h ** 2))
|
|
|
|
|
|
|
|
# 设置阈值
|
|
|
|
|
|
|
|
threshold = 120
|
|
|
|
|
|
|
|
mag[mag < threshold] = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mag = mag.astype(np.uint8)
|
|
|
|
|
|
|
|
return Image.fromarray(mag)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 人脸检测
|
|
|
|
|
|
|
|
def face_detect(img, path):
|
|
|
|
|
|
|
|
img = cv.imread(path)
|
|
|
|
|
|
|
|
name = path.split('.')[0]
|
|
|
|
|
|
|
|
print(img)
|
|
|
|
|
|
|
|
if (img.ndim == 3):
|
|
|
|
|
|
|
|
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
gray = img
|
|
|
|
|
|
|
|
face_cas = cv.CascadeClassifier('haarcascade_frontalface_default.xml')
|
|
|
|
|
|
|
|
face_scale = face_cas.detectMultiScale(gray, 1.1, 5, 0, (100, 100), (400, 400))
|
|
|
|
|
|
|
|
print(face_scale)
|
|
|
|
|
|
|
|
for (x, y, w, h) in face_scale:
|
|
|
|
|
|
|
|
cv.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 1)
|
|
|
|
|
|
|
|
cv.putText(img, name, (x + 10, y - 10), cv.FONT_HERSHEY_SIMPLEX, 1.2, (0, 255, 0), 1)
|
|
|
|
|
|
|
|
return Image.fromarray(img)
|