山东大学软件学院2018级项目实训 第七周-加入直方图
写在前面:之前实现的功能都需要滑块的辅助来实现
滑块的本质其实是根据滑块改变卷积核的大小来实现图像模糊,或者腐蚀膨胀
这周要加入的新功能有:1,绘制直方图 2,直方图均衡化
很显然,这两个功能并不需要滑块来传入数值,只需要点击鼠标传入信号调用函数即可
1,什么是直方图
简单地说,直方图可以视为图形或绘图,从而可以总体了解图像的强度分布。它是在X轴上具有像素值(不总是从0到255的范围),在Y轴上具有图像中相应像素数的图。
通过直方图,可以直观地了解该图像的对比度,亮度,强度分布等。当今几乎所有图像处理工具都提供直方图功能。
通俗的讲,直方图是图像中像素灰度值大小的频率分布。
(是不是和高中学习的频率分布直方图很像!)
2,绘制直方图
代码部分可以使用Matplotlib库实现:
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('photo.jpg',0)
plt.hist(img.ravel(),256,[0,256]); plt.show()
效果
接下来需要把这个功能放进我们的项目中来
1.首先,在图像菜单中添加直方图子选项
上一周的项目中图像菜单下只有“模糊” 和 “形态转换”两个功能
# 子菜单直方图中有两个选项,绘制直方图和直方图均衡化
change_menu3 = QMenu('直方图', instance)
change_menu3.addAction(histogram_draw_action)
change_menu3.addAction(histogram_equalization_action)
# 新增一个菜单选项:图像
# 图像选项新增一个子菜单直方图
menubar = instance.menuBar()
editMenu = menubar.addMenu('&图像')
editMenu.addMenu(change_menu1)
editMenu.addMenu(change_menu2)
# 添加子菜单选项change_menu3对应着直方图!
editMenu.addMenu(change_menu3)
效果:
不过这个时候的子菜单只是空有一个名字,是没有肉体和灵魂(功能)的
我们下一步要为他增加功能
2,创建一个窗口
在定义子菜单选项的位置增加对直方图的定义
因为不需要滑块,所以这里只需要定义显示窗口即可
# --------------------------直方图部分------------------------------------------------------------
# 绘制直方图
# 创建一个窗口,定义位置,标题等属性
instance.widegt_draw_histogram = QWidget()
instance.widegt_draw_histogram.setWindowTitle('绘制直方图')
# 创建一个action,当该action被触发时运行mean_blur_widegt_show
histogram_draw_action = QAction('&绘制直方图', instance)
# 直方图均衡化
# 创建一个窗口,定义位置,标题等属性
instance.widegt_equalization_histogram = QWidget()
instance.widegt_equalization_histogram.setWindowTitle('直方图均衡化')
# 创建一个action,当该action被触发时运行mean_blur_widegt_show
histogram_equalization_action = QAction('&直方图均衡化', instance)
到这里子菜单有了两幅躯壳但还没有灵魂
下一步我们需要对两个功能绘制和直方图均衡化进行区分,当点击不同功能时调用不同的函数
3,发射信号
首先一步的区分是为两个功能设定对象名:
# 设置名字,后面根据名字执行判断
histogram_draw_action.setObjectName("histogram_draw_action")
histogram_equalization_action.setObjectName("histogram_equalization_action")
# 具体实现的函数收到信号后还需要判断其来源,根据来源调用不同的函数
# 这里实现的方法很简单,根据对象名不同调用不同函数
发射信号:
# 上面定义了一个QAction,当触发这个行为之后和signal_emit_by_name_part2函数连接
histogram_draw_action.triggered.connect(instance.signal_emit_by_name_part2)
histogram_equalization_action.triggered.connect(instance.signal_emit_by_name_part2)
def signal_emit_by_name_part2(self):
m_blur.singal_emit_by_name(self,self.sender().objectName())
# signal_emit_by_name_part2收到信号后判断发射信号的对象名,紧接着调用singal_emit_by_name函数
# singal_emit_by_name通过调用具体函数来实现相关功能
# 我们在前面写的绘制直方图的方法在这里就可以派上用场了
def singal_emit_by_name(self, name):
if name == "histogram_draw_action":
fun_histogram_draw(self)
if name == "histogram_equalization_action":
fun_histogram_equalization(self)
绘制直方图的实现:
def fun_histogram_draw(instance):
print("绘制直方图")
plt.hist(instance.m_image.ravel(), 256, [0, 256])
plt.show()
3,直方图均衡化
前面的步骤完全重复一遍,在最后声明直方图均衡化函数即可
def fun_histogram_equalization(instance):
print("直方图均衡化")
img = instance.m_image
# 原本图像输入时改为了RGB格式,这里需要先改为YUV格式
img_yuv = cv.cvtColor(img, cv.COLOR_RGB2YUV)
# equalize the histogram of the Y channel
img_yuv[:, :, 0] = cv.equalizeHist(img_yuv[:, :, 0])
# convert the YUV image back to RGB format
img_output = cv.cvtColor(img_yuv, cv.COLOR_YUV2BGR)
cv.imshow('Histogram equalized', img_output)
cv.waitKey(0)
效果:
可以看到输入图像亮度偏低,均衡化后整体亮度有比较明显的提升,对比度也有提高