目录
2. UI 设计(这里只展示功能实现部分,自动生成的代码已省去)
参考资料:
PyQT6的从零开始(一):在Anaconda下安装PyQT6+在Pycharm中如何配置与使用-CSDN博客
数字图像处理之点运算---分段线性变换_jxqbuct的博客-CSDN博客
第3章 Python 数字图像处理(DIP) - 灰度变换与空间滤波4 - 分段线性变换 - 对比度拉伸_分段线性变换python_jasneik的博客-CSDN博客
PyQt5实现按键显示文件夹中图片_pyqt显示图像_木南成长之路的博客-CSDN博客
代码
1. 各种转换方法的实现
"""
该文件实现了1个计算个灰度值的像素个数函数
实现了5个转换函数(均保存并返回目标图片)
为了实现后续展示图片,下面每个变换函数都会将目标图像保存为 img/dst_img.png
"""
def histogram(img):
"""
计算各灰度值的像素个数
:param img: 原始灰度图
:return: n:各灰度值的像素个数
"""
H, W = img.shape[:2]
n = np.zeros(256)
# 循环遍历每个像素点
for i in range(H):
for j in range(W):
n[img[i][j]] += 1
return n
def histogram_equalization(img):
"""
直方图均衡化
:param img: 原始灰度图
:return: 直方图均衡化后的图
"""
H, W = img.shape[:2]
# 计算直方图
n = histogram(img)
# 计算直方图频率
p = n / (H*W)
# 计算累计频率
s = np.zeros(256)
sum = 0
for i in range(256):
s[i] = p[i] + sum
sum = s[i]
# 计算输出灰度
s = s * 255
# 创建新图片
dst_img = img.copy()
for i in range(H):
for j in range(W):
dst_img[i, j] = s[img[i, j]]
cv.imwrite('img/dst_img.png', dst_img)
return dst_img
def gray_reverse(img):
"""
灰度反转
:param img: 原始灰度图
:return: 灰度反转图
"""
dst_img = np.array(255-img) # 这里的 np.array 处理是为了防止 cv.imwrite 报错
cv.imwrite('img/dst_img.png', dst_img)
return dst_img
def linear_transform(img, x1, x2, y1, y2):
"""
用 opencv 实现分段线性变换
:return: 分段线性变换后的图
"""
lut = np.zeros(256)
for i in range(256):
if i < x1:
lut[i] = (y1 / x1) * i
elif i < x2:
lut[i] = ((y2 - y1) / (x2 - x1)) * (i - x1) + y1
else:
lut[i] = ((y2 - 255.0) / (x2 - 255.0)) * (i - 255.0) + 255.0
dst_img = cv.LUT(img, lut)
dst_img = np.uint8(dst_img + 0.5) # +0.5有它自己的道理吧,但是效果看不出来
cv.imwrite('img/dst_img.png', dst_img)
return dst_img
def log_transform(img, c=1):
"""
对数变换
:param img: 原始灰度图
:param c: 常数
:return: 对数变换的图
"""
s = c * np.log(1+img)
# 不知道为什么c的取值不会影响最终的图片效果,可能和下面的缩放处理有关
# 缩放
sm = s - s.min()
dst_img = (sm / sm.max()) * 255
dst_img = np.uint8(dst_img + 0.5)
cv.imwrite('img/dst_img.png', dst_img)
return dst_img
def power_transform(img, c, gamma):
"""
伽马变换
:param img: 原始灰度图
:param c: 常数
:param gamma:常数,次方
:return:伽马变换后的图
"""
s = c * pow(img, gamma)
# 缩放
sm = s - s.min()
dst_img = (sm / sm.max()) * 255
dst_img = np.uint8(dst_img + 0.5)
cv.imwrite('img/dst_img.png', dst_img)
return dst_img
# # 测试函数功能
# if __name__ == "__main__":
# # 读入灰度图
# org_img = cv.imread('img.png')
# print(org_img.shape)
# # 绘制直方图
# n = histogram(org_img)
# plt.bar(range(256), n)
# plt.show()
# # 灰度反转
# rvs_img = gray_reverse(org_img)
# # 直方图均衡化
# equ_img = histogram_equalization(org_img)
# histogram(equ_img)
# # 线性变换
# # 这里的参数可以调整,当前参数对课件上图片效果较好
# lin_img = linear_transform(org_img, 50, 200, 80, 230)
#
# log_img = log_transform(org_img)
#
# pow_img = power_transform(org_img, 1, 0.4)
# # 通过 imshow 显示图片
# cv.imshow("origin_img", org_img)
# cv.imshow("pow_img", pow_img)
# cv.imshow("rvs_img", rvs_img)
# cv.imshow("equ_img", equ_img)
# cv.waitKey(0)
2. UI 设计(这里只展示功能实现部分,自动生成的代码已省去)
"""
这里使用了PyQt6进行UI设计
使用了GTDesigner工具(可视化制作GUI)和pyUIC工具(将QTdesigner中生成的.ui文件转换为.py文件)
"""
# 保存直方图
def save_histogram(img, name):
n = histogram(img)
plt.bar(range(256), n)
# 为了方便,这里的 name 其实只有两种:原图直方图和转换后直方图
img_path = './img/{}.png'.format(name)
plt.savefig(img_path) # 保存直方图
plt.cla() # 清除之前的plt,否则会一直保留之前生成过的直方图
return img_path # 因为后面 QPixmap 需要用到图片地址
class Ui_Dialog(object):
def __init__(self):
self.org_img = None # 保存选择的原始灰度图
# 自动生成
def setupUi(self, Dialog):
# 省略
# 设定按钮的功能
self.button_connect()
# 自动生成
def retranslateUi(self, Dialog):
# 省略
# 给每个按钮加上点击功能
def button_connect(self):
self.pushButton.clicked.connect(self.open_img)
self.pushButton_3.clicked.connect(lambda: self.show_dst_img(3))
self.pushButton_4.clicked.connect(lambda: self.show_dst_img(4))
self.pushButton_5.clicked.connect(lambda: self.show_dst_img(5))
self.pushButton_6.clicked.connect(lambda: self.show_dst_img(6))
self.pushButton_7.clicked.connect(lambda: self.show_dst_img(7))
# 打开图片
def open_img(self):
imgName, imgType = QFileDialog.getOpenFileName(None, "打开图片", "lab02/img/", "*.png;;*.jpg;;All Files(*)")
self.org_img = cv.imread(imgName)
# 显示图片
pix = QPixmap(imgName).scaled(self.label_5.width(), self.label_5.height())
self.label_5.setPixmap(pix)
# 显示直方图
his_imgName = save_histogram(self.org_img, '原图直方图')
pix = QPixmap(his_imgName).scaled(self.label_3.width(), self.label_3.height())
self.label_3.setPixmap(pix)
# 显示转换后的图片及直方图
def show_dst_img(self, x):
if x == 3:
gray_reverse(self.org_img)
elif x == 4:
histogram_equalization(self.org_img)
elif x == 5:
# 由于 ui 没有设计可以传递参数的入口,这里使用固定参数
linear_transform(self.org_img, 50, 200, 80, 230)
elif x == 6:
# 由于 ui 没有设计可以传递参数的入口,这里使用固定参数
power_transform(self.org_img, 1, 0.4)
elif x == 7:
log_transform(self.org_img)
dst_img = cv.imread('img/dst_img.png')
# 显示图片
pix = QPixmap('img/dst_img.png').scaled(self.label_6.width(), self.label_6.height())
self.label_6.setPixmap(pix)
# 显示直方图
his_imgName = save_histogram(dst_img, '转换后直方图')
pix = QPixmap(his_imgName).scaled(self.label_4.width(), self.label_4.height())
self.label_4.setPixmap(pix)
3. 启动程序
if __name__ == '__main__':
# 创建ui,引用 Ui_MainWindow类
app = QApplication(sys.argv)
mainWindow = QMainWindow()
ui = ui_sys.Ui_Dialog()
# 调用 setupUi,创建初始组件
ui.setupUi(mainWindow)
# 创建窗口
mainWindow.show()
# 进入程序的主循环,并通过exit函数确保主循环安全结束(该释放资源的一定要释放)
sys.exit(app.exec())
注:
第一次接触pyqt,效果可能实现了但是代码质量不一定高