|
|
from tkinter import *
|
|
|
from tkinter import messagebox
|
|
|
from tkinter.filedialog import *
|
|
|
from tkinter.colorchooser import *
|
|
|
import numpy as np
|
|
|
import cv2
|
|
|
import cv2 as cv
|
|
|
import sys
|
|
|
from PIL import Image, ImageTk
|
|
|
import matplotlib.pyplot
|
|
|
import matplotlib.pyplot as plt
|
|
|
from PIL.Image import Resampling
|
|
|
global out_path
|
|
|
out_path="img/output/test.png"
|
|
|
|
|
|
class Application(Frame):
|
|
|
def __init__(self, master=None):
|
|
|
super().__init__(master)
|
|
|
self.master = master
|
|
|
self.textpad = None
|
|
|
self.place()
|
|
|
self.createWidget()
|
|
|
|
|
|
def test(self):
|
|
|
pass
|
|
|
|
|
|
def createWidget(self):
|
|
|
|
|
|
menubar = Menu(root)
|
|
|
menuFile = Menu(menubar)
|
|
|
menuNoise = Menu(menubar)
|
|
|
menuDetect = Menu(menubar)
|
|
|
menuBinary = Menu(menubar)
|
|
|
空域的平滑 = Menu(menubar)
|
|
|
频域的平滑 = Menu(menubar)
|
|
|
数字图像直方图 = Menu(menubar)
|
|
|
|
|
|
menubar.add_cascade(label="文件", menu=menuFile)
|
|
|
menubar.add_cascade(label="线条变化检测与边缘检测", menu=menuDetect)
|
|
|
menubar.add_cascade(label="噪声滤除", menu=menuNoise)
|
|
|
menubar.add_cascade(label="数字图像形态学", menu=menuBinary)
|
|
|
menubar.add_cascade(label="空域的平滑", menu=空域的平滑)
|
|
|
menubar.add_cascade(label="频域的平滑", menu=频域的平滑)
|
|
|
menubar.add_cascade(label="数字图像直方图", menu=数字图像直方图)
|
|
|
|
|
|
menuFile.add_command(label="打开", command=self.openfile)
|
|
|
menuFile.add_command(label="保存", command=self.savefile)
|
|
|
|
|
|
menuDetect.add_command(label="线条变化检测", command=self.线条变化检测)
|
|
|
menuDetect.add_command(label="边缘检测的基本原理和图像增强", command=self.边缘检测的基本原理和图像增强)
|
|
|
menuDetect.add_command(label="Roberts算子", command=self.Roberts算子)
|
|
|
menuDetect.add_command(label="Prewitt算子与Sobel算子", command=self.Prewitt算子与Sobel算子)
|
|
|
menuDetect.add_command(label="Laplacian算子", command=self.Laplacian算子)
|
|
|
menuDetect.add_command(label="LoG边缘算子", command=self.LoG边缘算子)
|
|
|
menuDetect.add_command(label="Canny边缘检测", command=self.Canny边缘检测)
|
|
|
|
|
|
menuNoise.add_command(label="噪声描述器", command=self.噪声描述器)
|
|
|
menuNoise.add_command(label="均值类滤波器", command=self.均值类滤波器)
|
|
|
menuNoise.add_command(label="排序统计类滤波器", command=self.排序统计类滤波器)
|
|
|
menuNoise.add_command(label="选择性滤波器", command=self.选择性滤波器)
|
|
|
|
|
|
menuBinary.add_command(label="腐蚀", command=self.腐蚀)
|
|
|
menuBinary.add_command(label="膨胀", command=self.膨胀)
|
|
|
menuBinary.add_command(label="开运算", command=self.开运算)
|
|
|
menuBinary.add_command(label="闭运算", command=self.闭运算)
|
|
|
|
|
|
频域的平滑.add_command(label="理想低通滤波", command=self.理想低通滤波)
|
|
|
频域的平滑.add_command(label="巴特沃斯低通滤波", command=self.巴特沃斯低通滤波)
|
|
|
频域的平滑.add_command(label="高斯低通滤波", command=self.高斯低通滤波)
|
|
|
|
|
|
空域的平滑.add_command(label="均值滤波", command=self.均值滤波)
|
|
|
空域的平滑.add_command(label="中值滤波", command=self.中值滤波)
|
|
|
|
|
|
数字图像直方图.add_command(label="灰度直方图", command=self.灰度直方图)
|
|
|
数字图像直方图.add_command(label="彩色直方图", command=self.彩色直方图)
|
|
|
数字图像直方图.add_command(label="绘制直方图", command=self.绘制直方图)
|
|
|
数字图像直方图.add_command(label="分段线性变换对直方图修改", command=self.分段线性变换对直方图修改)
|
|
|
|
|
|
root["menu"] = menubar
|
|
|
|
|
|
self.original_label = Label(text="原始图片")
|
|
|
self.original_label.place(x=50, y=50)
|
|
|
|
|
|
self.edited_label = Label(text="处理后的图片")
|
|
|
self.edited_label.place(x=550, y=50)
|
|
|
|
|
|
global original_canvas # 展示原始图片的画布
|
|
|
self.original_canvas = Canvas(width=500, height=500, bg='blue', bd=0)
|
|
|
self.original_canvas.place(x=50, y=100)
|
|
|
global edited_canvas # 展示处理后的图片的画布
|
|
|
self.edited_canvas = Canvas(width=500, height=500, bg='blue', bd=0)
|
|
|
self.edited_canvas.place(x=550, y=100)
|
|
|
|
|
|
def img_resize(self, image):
|
|
|
"""在APP页面展示图片需要调整图片大小,使图片按照原比例放在画布组件内"""
|
|
|
w, h = image.size
|
|
|
if h > w:
|
|
|
target_size = (int(500*(w/h)), 500)
|
|
|
else:
|
|
|
target_size = (500, int(500*(h/w)))
|
|
|
scale_img = image.copy()
|
|
|
out = scale_img.resize(target_size, Resampling.LANCZOS)
|
|
|
return out
|
|
|
|
|
|
def openfile(self):
|
|
|
"""
|
|
|
使用askopenfile获取文件路径,在canvas中展示使用Image.open和ImageTk.PhotoImage打开,
|
|
|
而在opencv处理图片时使用cv2.imwrite(path)直接打开图片
|
|
|
"""
|
|
|
with askopenfile(title="打开图片") as f:
|
|
|
global img_1, img_2
|
|
|
global path
|
|
|
path = f.name
|
|
|
img_1 = Image.open(path)
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
original_img = ImageTk.PhotoImage(img_2)
|
|
|
self.original_canvas.create_image(251, 253, image=original_img)
|
|
|
self.original_canvas.image = original_img
|
|
|
self.edited_canvas.delete("all")
|
|
|
root.update()
|
|
|
|
|
|
def savefile(self):
|
|
|
"""
|
|
|
使用asksaveasfilename获取文件名,使用image.save进行保存
|
|
|
这样做的好处是:可以自定义储存的文件名以及后缀,避免固定文件
|
|
|
名带来后续保存覆盖之前的保存的问题
|
|
|
"""
|
|
|
out_path = asksaveasfilename(title="保存图片")
|
|
|
cv2.imwrite(out_path, output)
|
|
|
|
|
|
def get_max(self, arr):
|
|
|
# 列表的长度
|
|
|
length = len(arr)
|
|
|
# 对列表进行选择排序,获得有序的列表
|
|
|
for i in range(length):
|
|
|
for j in range(i + 1, length):
|
|
|
# 选择最大的值
|
|
|
if arr[j] > arr[i]:
|
|
|
# 交换位置
|
|
|
temp = arr[j]
|
|
|
arr[j] = arr[i]
|
|
|
arr[i] = temp
|
|
|
return arr[0]
|
|
|
|
|
|
def 噪声描述器(self):
|
|
|
image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
|
|
|
global output
|
|
|
output = np.zeros(image.shape, np.uint8)
|
|
|
for i in range(image.shape[0]):
|
|
|
for j in range(image.shape[1]):
|
|
|
# 添加食盐噪声
|
|
|
if image[i][j] < 100:
|
|
|
output[i][j] = 255
|
|
|
|
|
|
# 添加胡椒噪声
|
|
|
elif image[i][j] > 200:
|
|
|
output[i][j] = 0
|
|
|
# 不添加噪声
|
|
|
else:
|
|
|
output[i][j] = image[i][j]
|
|
|
img_1 = Image.fromarray(np.uint8(output))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 均值类滤波器(self):
|
|
|
image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
|
|
|
global output
|
|
|
output = np.zeros(image.shape, np.uint8)
|
|
|
for i in range(image.shape[0]):
|
|
|
for j in range(image.shape[1]):
|
|
|
ji = 1.0
|
|
|
for m in range(-1, 2):
|
|
|
if 0 <= j + m < image.shape[1]:
|
|
|
ji *= image[i][j + m]
|
|
|
output[i][j] = ji ** (1 / 3)
|
|
|
img_1 = Image.fromarray(np.uint8(output))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 排序统计类滤波器(self):
|
|
|
image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
|
|
|
array = []
|
|
|
global output
|
|
|
output = np.zeros(image.shape, np.uint8)
|
|
|
for i in range(image.shape[0]):
|
|
|
for j in range(image.shape[1]):
|
|
|
# 最大值滤波器
|
|
|
array.clear()
|
|
|
for m in range(-1, 2):
|
|
|
for n in range(-1, 2):
|
|
|
if 0 <= i + m < image.shape[0] and 0 <= j + n < image.shape[1]:
|
|
|
array.append(image[i + m][j + n])
|
|
|
output[i][j] = self.get_max(arr=array)
|
|
|
img_1 = Image.fromarray(np.uint8(output))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 选择性滤波器(self):
|
|
|
image = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
|
|
|
global output
|
|
|
output = np.zeros(image.shape, np.uint8)
|
|
|
for i in range(image.shape[0]):
|
|
|
for j in range(image.shape[1]):
|
|
|
if image[i][j] > 200:
|
|
|
output[i][j] = image[i][j]
|
|
|
else:
|
|
|
output[i][j] = 0
|
|
|
img_1 = Image.fromarray(np.uint8(output))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 线条变化检测(self):
|
|
|
img = cv2.imread(path)
|
|
|
img = cv2.GaussianBlur(img, (3, 3), 0)
|
|
|
edges = cv2.Canny(img, 50, 150, apertureSize=3)
|
|
|
lines = cv2.HoughLines(edges, 1, np.pi / 2, 118)
|
|
|
result = img.copy()
|
|
|
for i_line in lines:
|
|
|
for line in i_line:
|
|
|
rho = line[0]
|
|
|
theta = line[1]
|
|
|
if (theta < (np.pi / 4.)) or (theta > (3. * np.pi / 4.0)): # 垂直直线
|
|
|
pt1 = (int(rho / np.cos(theta)), 0)
|
|
|
pt2 = (int((rho - result.shape[0] * np.sin(theta)) / np.cos(theta)), result.shape[0])
|
|
|
cv2.line(result, pt1, pt2, (0, 0, 255))
|
|
|
else:
|
|
|
pt1 = (0, int(rho / np.sin(theta)))
|
|
|
pt2 = (result.shape[1], int((rho - result.shape[1] * np.cos(theta)) / np.sin(theta)))
|
|
|
cv2.line(result, pt1, pt2, (0, 0, 255), 1)
|
|
|
minLineLength = 200
|
|
|
maxLineGap = 15
|
|
|
linesP = cv2.HoughLinesP(edges, 1, np.pi / 180, 80, minLineLength, maxLineGap)
|
|
|
result_P = img.copy()
|
|
|
for i_P in linesP:
|
|
|
for x1, y1, x2, y2 in i_P:
|
|
|
cv2.line(result_P, (x1, y1), (x2, y2), (0, 255, 0), 3)
|
|
|
|
|
|
global output
|
|
|
output = result_P
|
|
|
img_1 = Image.fromarray(np.uint8(result_P))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 边缘检测的基本原理和图像增强(self):
|
|
|
CRH = cv2.imread(path, 0)
|
|
|
CRH = CRH.astype('float')
|
|
|
h, w = CRH.shape
|
|
|
gradient = np.zeros((h, w))
|
|
|
gradient = gradient.astype('float')
|
|
|
for x in range(h - 1):
|
|
|
for y in range(w - 1):
|
|
|
gx = abs(CRH[x + 1, y] - CRH[x, y])
|
|
|
gy = abs(CRH[x, y + 1] - CRH[x, y])
|
|
|
gradient[x, y] = gx + gy
|
|
|
sharp = CRH + gradient
|
|
|
sharp = np.where(sharp > 255, 255, sharp)
|
|
|
sharp = np.where(sharp < 0, 0, sharp)
|
|
|
gradient = gradient.astype('uint8')
|
|
|
sharp = sharp.astype('uint8')
|
|
|
global output
|
|
|
output = gradient
|
|
|
img_1 = Image.fromarray(np.uint8(gradient))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def Roberts算子(self):
|
|
|
img = cv2.imread(path)
|
|
|
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
|
kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
|
|
|
kernely = np.array([[0, -1], [1, 0]], dtype=int)
|
|
|
x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
|
|
|
y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
|
|
|
absX = cv2.convertScaleAbs(x)
|
|
|
absY = cv2.convertScaleAbs(y)
|
|
|
Roberts = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
|
|
|
global output
|
|
|
output = Roberts
|
|
|
img_1 = Image.fromarray(np.uint8(Roberts))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def Prewitt算子与Sobel算子(self):
|
|
|
img = cv2.imread(path)
|
|
|
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
|
kernelx = cv2.Sobel(grayImage, cv2.CV_16S, 1, 0)
|
|
|
kernely = cv2.Sobel(grayImage, cv2.CV_16S, 0, 1)
|
|
|
x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
|
|
|
y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
|
|
|
absX = cv2.convertScaleAbs(x)
|
|
|
absY = cv2.convertScaleAbs(y)
|
|
|
Sobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
|
|
|
global output
|
|
|
output = Sobel
|
|
|
img_1 = Image.fromarray(np.uint8(Sobel))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def Laplacian算子(self):
|
|
|
img = cv2.imread(path)
|
|
|
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
|
|
img_gaussianBlur = cv2.GaussianBlur(grayImage, (5, 5), 0)
|
|
|
dst = cv2.Laplacian(img_gaussianBlur, cv2.CV_16S, ksize=3)
|
|
|
Laplacian = cv2.convertScaleAbs(dst)
|
|
|
global output
|
|
|
output = Laplacian
|
|
|
img_1 = Image.fromarray(np.uint8(Laplacian))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def LoG边缘算子(self):
|
|
|
img = cv2.imread(path)
|
|
|
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
|
|
img = cv2.copyMakeBorder(grayImage, 2, 2, 2, 2, borderType=cv2.BORDER_REPLICATE)
|
|
|
img = cv2.GaussianBlur(img, (3, 3), 0, 0)
|
|
|
m1 = np.array(
|
|
|
[[0, 0, -1, 0, 0], [0, -1, -2, -1, 0], [-1, -2, 16, -2, -1], [0, -1, -2, -1, 0], [0, 0, -1, 0, 0]],
|
|
|
dtype=np.int32)
|
|
|
image1 = np.zeros(img.shape).astype(np.int32)
|
|
|
h, w, _ = img.shape
|
|
|
for i in range(2, h - 2):
|
|
|
for j in range(2, w - 2):
|
|
|
image1[i, j] = np.sum(m1 * img[i - 2:i + 3, j - 2:j + 3, 1])
|
|
|
global output
|
|
|
output = image1
|
|
|
img_1 = Image.fromarray(np.uint8(image1))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def Canny边缘检测(self):
|
|
|
src = cv2.imread(path)
|
|
|
blur = cv2.GaussianBlur(src, (3, 3), 0)
|
|
|
grayImage = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
|
|
|
gradx = cv2.Sobel(grayImage, cv2.CV_16SC1, 1, 0)
|
|
|
grady = cv2.Sobel(grayImage, cv2.CV_16SC1, 0, 1)
|
|
|
edge_output = cv2.Canny(gradx, grady, 50, 150)
|
|
|
global output
|
|
|
output = edge_output
|
|
|
img_1 = Image.fromarray(np.uint8(edge_output))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 腐蚀(self):
|
|
|
src = cv2.imread(path, cv2.IMREAD_UNCHANGED)
|
|
|
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
|
|
|
erosion = cv2.erode(src, kernel)
|
|
|
global output
|
|
|
output = erosion
|
|
|
img_1 = Image.fromarray(np.uint8(erosion))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 膨胀(self):
|
|
|
src = cv2.imread(path, cv2.IMREAD_UNCHANGED)
|
|
|
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
|
|
|
dilation = cv2.dilate(src, kernel)
|
|
|
global output
|
|
|
output = dilation
|
|
|
img_1 = Image.fromarray(np.uint8(dilation))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 开运算(self):
|
|
|
src = cv2.imread(path, cv2.IMREAD_UNCHANGED)
|
|
|
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))
|
|
|
open = cv2.morphologyEx(src, cv2.MORPH_OPEN, kernel)
|
|
|
global output
|
|
|
output = open
|
|
|
img_1 = Image.fromarray(np.uint8(open))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 闭运算(self):
|
|
|
src = cv2.imread(path, cv2.IMREAD_UNCHANGED)
|
|
|
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (10, 10))
|
|
|
close = cv2.morphologyEx(src, cv2.MORPH_CLOSE, kernel)
|
|
|
global output
|
|
|
output = close
|
|
|
img_1 = Image.fromarray(np.uint8(close))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 理想低通滤波(self):
|
|
|
img = cv2.imread(path)
|
|
|
img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
|
|
|
img = np.float32(img)
|
|
|
dft = cv2.dft(img, flags=cv2.DFT_COMPLEX_OUTPUT)
|
|
|
dft = np.fft.fftshift(dft)
|
|
|
rows, cols = img.shape
|
|
|
mask = np.zeros((rows, cols, 2))
|
|
|
mask[int(rows / 2) - 20:int(rows / 2) + 20, int(cols / 2) - 20:int(cols / 2) + 20] = 1
|
|
|
f = dft * mask
|
|
|
f = np.fft.ifftshift(f)
|
|
|
img = cv2.idft(f)
|
|
|
img = cv2.magnitude(img[:, :, 0], img[:, :, 1])
|
|
|
global output
|
|
|
output = img
|
|
|
img_1 = Image.fromarray(np.uint8(img))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 巴特沃斯低通滤波(self):
|
|
|
img = cv2.imread(path)
|
|
|
img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
|
|
|
img = np.float32(img)
|
|
|
dft = cv2.dft(img, flags=cv2.DFT_COMPLEX_OUTPUT)
|
|
|
dft = np.fft.fftshift(dft)
|
|
|
rows, cols = img.shape
|
|
|
mask = np.zeros((rows, cols, 2))
|
|
|
D0 = 20
|
|
|
N = 2
|
|
|
for i in range(rows):
|
|
|
for j in range(cols):
|
|
|
D = np.sqrt((i - rows / 2) ** 2 + (j - cols / 2) ** 2)
|
|
|
mask[i, j, 0] = mask[i, j, 1] = 1.0 / (1.0 + ((D / D0) ** (2 * N)))
|
|
|
f = dft * mask
|
|
|
f = np.fft.ifftshift(f)
|
|
|
img = cv2.idft(f)
|
|
|
img = cv2.magnitude(img[:, :, 0], img[:, :, 1])
|
|
|
global output
|
|
|
output = img
|
|
|
img_1 = Image.fromarray(np.uint8(img))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 高斯低通滤波(self):
|
|
|
img = cv2.imread(path)
|
|
|
img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
|
|
|
img = np.float32(img)
|
|
|
dft = cv2.dft(img, flags=cv2.DFT_COMPLEX_OUTPUT)
|
|
|
dft = np.fft.fftshift(dft)
|
|
|
rows, cols = img.shape
|
|
|
crow, ccol = int(rows / 2), int(cols / 2)
|
|
|
mask = np.zeros((rows, cols, 2))
|
|
|
D0 = 20
|
|
|
for i in range(rows):
|
|
|
for j in range(cols):
|
|
|
D = np.sqrt((i - crow) ** 2 + (j - ccol) ** 2)
|
|
|
mask[i, j, 0] = mask[i, j, 1] = np.exp(-(D * D) / (2 * D0 * D0))
|
|
|
f = dft * mask
|
|
|
f = np.fft.ifftshift(f)
|
|
|
img = cv2.idft(f)
|
|
|
img = cv2.magnitude(img[:, :, 0], img[:, :, 1])
|
|
|
global output
|
|
|
output = img
|
|
|
img_1 = Image.fromarray(np.uint8(img))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 中值滤波(self):
|
|
|
img = cv2.imread(path)
|
|
|
mid_blur = cv2.medianBlur(img, 3)
|
|
|
global output
|
|
|
output = mid_blur
|
|
|
img_1 = Image.fromarray(np.uint8(mid_blur))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 均值滤波(self):
|
|
|
img = cv2.imread(path)
|
|
|
avg_blur = cv2.blur(img, (3, 3))
|
|
|
global output
|
|
|
output = avg_blur
|
|
|
img_1 = Image.fromarray(np.uint8(avg_blur))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
|
|
|
def 灰度直方图(self):
|
|
|
fileName = 'img/output/灰度直方图的计算-默认输出.png'
|
|
|
img = cv.imread(path, 0)
|
|
|
plt.figure(fileName, figsize=(16, 8))
|
|
|
plt.subplot(121)
|
|
|
plt.imshow(img, "gray")
|
|
|
plt.subplot(122)
|
|
|
hist = cv.calcHist([img], [0], None, [256], [0, 255])
|
|
|
plt.plot(hist)
|
|
|
plt.xlim([0, 255])
|
|
|
img_1 = Image.fromarray(np.uint8(img))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
plt.savefig(fileName)
|
|
|
plt.show()
|
|
|
|
|
|
def 彩色直方图(self):
|
|
|
imgOri1 = cv2.imread(path)
|
|
|
fileName = 'img/output/彩色直方图的计算-默认输出.png'
|
|
|
color = ["r", "g", "b"]
|
|
|
img_rgb2 = cv2.cvtColor(imgOri1, cv2.COLOR_BGR2RGB)
|
|
|
plt.subplot(121)
|
|
|
plt.imshow(imgOri1)
|
|
|
plt.subplot(122)
|
|
|
for index, c in enumerate(color):
|
|
|
hist = cv2.calcHist([img_rgb2], [index], None, [256], [0, 255])
|
|
|
plt.plot(hist, color=c)
|
|
|
plt.xlim([0, 255])
|
|
|
img_1 = Image.fromarray(np.uint8(img_rgb2))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
plt.savefig(fileName)
|
|
|
plt.show()
|
|
|
|
|
|
def 绘制直方图(self):
|
|
|
img = cv2.imread(path)
|
|
|
b, g, r = cv2.split(img)
|
|
|
hist = cv2.calcHist([b], [0], None, [256], [0, 256])
|
|
|
plt.plot(hist, color='blue')
|
|
|
plt.xlim([0, 256])
|
|
|
hist = cv2.calcHist([g], [0], None, [256], [0, 256])
|
|
|
plt.plot(hist, color='green')
|
|
|
plt.xlim([0, 256])
|
|
|
hist = cv2.calcHist([r], [0], None, [256], [0, 256])
|
|
|
plt.plot(hist, color='red')
|
|
|
plt.xlim([0, 256])
|
|
|
img_1 = Image.fromarray(np.uint8(img))
|
|
|
img_2 = self.img_resize(img_1)
|
|
|
edited_img = ImageTk.PhotoImage(img_2)
|
|
|
self.edited_canvas.create_image(253, 253, image=edited_img)
|
|
|
self.edited_canvas.image = edited_img
|
|
|
plt.savefig('img/output/绘制直方图-默认输出')
|
|
|
|
|
|
def grayHist(self, img, filename):
|
|
|
plt.figure(filename, figsize=(16, 8))
|
|
|
plt.subplot(121)
|
|
|
plt.imshow(img, 'gray')
|
|
|
plt.subplot(122)
|
|
|
h, w = img.shape[:2]
|
|
|
pixelSequence = img.reshape(1, -1)
|
|
|
numberBins = 256
|
|
|
histogram, bins, patch = plt.hist(img.ravel(), 256, range=[0, 256])
|
|
|
print(max(histogram))
|
|
|
plt.xlabel("gray label")
|
|
|
plt.ylabel("number of pixels")
|
|
|
plt.axis([0, 255, 0, np.max(histogram)])
|
|
|
plt.savefig(filename)
|
|
|
plt.show()
|
|
|
|
|
|
def 分段线性变换对直方图修改(self):
|
|
|
img_path = path
|
|
|
out_path = 'img/output/分段线性变换_1'
|
|
|
out2_path = 'img/output/分段线性变换_2'
|
|
|
img = cv2.imread(img_path, 0)
|
|
|
h, w = img.shape[:2]
|
|
|
out = np.zeros(img.shape, np.uint8)
|
|
|
|
|
|
for i in range(h):
|
|
|
for j in range(w):
|
|
|
if img[i][j] < 50:
|
|
|
out[i][j] = 0.5 * img[i][j]
|
|
|
elif img[i][j] < 150:
|
|
|
out[i][j] = 3.6 * img[i][j] - 310
|
|
|
else:
|
|
|
out[i][j] = 0.238 * img[i][j] + 194
|
|
|
|
|
|
out = np.around(out)
|
|
|
out = out.astype(np.uint8)
|
|
|
self.grayHist(img, out_path)
|
|
|
self.grayHist(out, out2_path)
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
root = Tk()
|
|
|
screen_width = root.winfo_screenwidth()
|
|
|
screen_height = root.winfo_screenheight()
|
|
|
root.geometry(f"1100x700+{int(0.5*(screen_width-1100))}+{int(0.5*(screen_height-700))}") #居中窗口
|
|
|
root.resizable(width=False, height=False)
|
|
|
root.title("数字图像处理")
|
|
|
app = Application(master=root)
|
|
|
|
|
|
root.mainloop()
|