写点什么

Python 从零到壹丨图像增强及运算:图像掩膜直方图和 HS 直方图

  • 2023-01-31
    中国香港
  • 本文字数:3884 字

    阅读完需:约 13 分钟

Python从零到壹丨图像增强及运算:图像掩膜直方图和HS直方图

本文分享自华为云社区《[Python从零到壹] 五十二.图像增强及运算篇之图像掩膜直方图和HS直方图》,作者: eastmount。

一.图像掩膜直方图


如果要统计图像的某一部分直方图,就需要使用掩码(蒙板)来进行计算。假设将要统计的部分设置为白色,其余部分设置为黑色,然后使用该掩膜进行直方图绘制,其完整代码如下所示。


# -*- coding: utf-8 -*-# By:Eastmountimport cv2  import numpy as npimport matplotlib.pyplot as pltimport matplotlib
#读取图像img = cv2.imread('luo.png')
#转换为RGB图像img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#设置掩膜mask = np.zeros(img.shape[:2], np.uint8)mask[100:300, 100:300] = 255masked_img = cv2.bitwise_and(img, img, mask=mask)
#图像直方图计算hist_full = cv2.calcHist([img], [0], None, [256], [0,256]) #通道[0]-灰度图
#图像直方图计算(含掩膜)hist_mask = cv2.calcHist([img], [0], mask, [256], [0,256])
plt.figure(figsize=(8, 6))
#设置字体matplotlib.rcParams['font.sans-serif']=['SimHei']
#原始图像plt.subplot(221)plt.imshow(img_rgb, 'gray')plt.axis('off')plt.title("(a)原始图像")
#绘制掩膜plt.subplot(222)plt.imshow(mask, 'gray')plt.axis('off')plt.title("(b)掩膜")
#绘制掩膜设置后的图像plt.subplot(223)plt.imshow(masked_img, 'gray')plt.axis('off')plt.title("(c)图像掩膜处理")
#绘制直方图plt.subplot(224)plt.plot(hist_full)plt.plot(hist_mask)plt.title("(d)直方图曲线")plt.xlabel("x")plt.ylabel("y")plt.show()
复制代码


其运行结果如图 1 所示,它使用了一个 200×200 像素的掩膜进行实验。其中图 1(a)表示原始图像,图 1(b)表示 200×200 像素的掩膜,图 1©表示原始图像进行掩膜处理,图 1(d)表示直方图曲线,蓝色曲线为原始图像的灰度值直方图分布情况,绿色波动更小的曲线为掩膜直方图曲线。


二.图像 HS 直方图


为了刻画图像中颜色的直观特性,常常需要分析图像的 HSV 空间下的直方图特性。HSV 空间是由色调(Hue)、饱和度(Saturation)、以及亮度(Value)构成,因此在进行直方图计算时,需要先将源 RGB 图像转化为 HSV 颜色空间图像,然后将对应的 H 和 S 通道进行单元划分,再其二维空间上计算相对应直方图,再计算直方图空间上的最大值并归一化绘制相应的直方图信息,从而形成色调-饱和度直方图(或 H-S 直方图)。该直方图通常应用在目标检测、特征分析以及目标特征跟踪等场景[1-2]。


由于 H 和 S 分量与人感受颜色的方式是紧密相连,V 分量与图像的彩色信息无关,这些特点使得 HSV 模型非常适合于借助人的视觉系统来感知彩色特性的图像处理算法。


下面的代码是具体的实现代码,使用 matplotlib.pyplot 库中的 imshow()函数来绘制具有不同颜色映射的 2D 直方图。


# -*- coding: utf-8 -*-# By:Eastmountimport cv2  import numpy as npimport matplotlib.pyplot as plt
#读取图像img = cv2.imread('luo.png')
#转换为RGB图像img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#图像HSV转换hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
#计算H-S直方图hist = cv2.calcHist(hsv, [0,1], None, [180,256], [0,180,0,256])
#原始图像plt.figure(figsize=(8, 6))plt.subplot(121), plt.imshow(img_rgb, 'gray'), plt.title("(a)"), plt.axis('off')
#绘制H-S直方图plt.subplot(122), plt.imshow(hist, interpolation='nearest'), plt.title("(b)")plt.xlabel("x"), plt.ylabel("y")plt.show()
复制代码


图 2(a)表示原始输入图像,图 2(b)是原图像对应的彩色直方图,其中 X 轴表示饱和度(S),Y 轴表示色调(H)。在直方图中,可以看到 H=140 和 S=130 附近的一些高值,它对应于艳丽的色调。


三.直方图判断白天黑夜


接着讲述一个应用直方图的案例,通过直方图来判断一幅图像是黑夜或白天。常见的方法是通过计算图像的灰度平均值、灰度中值或灰度标准差,再与自定义的阈值进行对比,从而判断是黑夜还是白天[3-4]。


  • 灰度平均值:该值等于图像中所有像素灰度值之和除以图像的像素个数。

  • 灰度中值:对图像中所有像素灰度值进行排序,然后获取所有像素最中间的值,即为灰度中值。

  • 灰度标准差:又常称均方差,是离均差平方的算术平均数的平方根。标准差能反映一个数据集的离散程度,是总体各单位标准值与其平均数离差平方的算术平均数的平方根。如果一幅图看起来灰蒙蒙的, 那灰度标准差就小;如果一幅图看起来很鲜艳,那对比度就很大,标准差也大。


下面的代码是计算灰度“Lena”图的灰度平均值、灰度中值和灰度标准差。


# -*- coding: utf-8 -*-# By:Eastmountimport cv2  import numpy as npimport matplotlib.pyplot as plt
#函数: 获取图像的灰度平均值def fun_mean(img, height, width): sum_img = 0 for i in range(height): for j in range(width): sum_img = sum_img + int(img[i,j]) mean = sum_img / (height * width) return mean
#函数: 获取中位数def fun_median(data): length = len(data) data.sort() if (length % 2)== 1: z = length // 2 y = data[z] else: y = (int(data[length//2]) + int(data[length//2-1])) / 2 return y
#读取图像img = cv2.imread('lena-hd.png')
#图像灰度转换grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#获取图像高度和宽度height = grayImage.shape[0]width = grayImage.shape[1]
#计算图像的灰度平均值mean = fun_mean(grayImage, height, width)print("灰度平均值:", mean)
#计算图像的灰度中位数value = grayImage.ravel() #获取所有像素值median = fun_median(value)print("灰度中值:", median)
#计算图像的灰度标准差std = np.std(value, ddof = 1)print("灰度标准差", std)
复制代码


其运行结果如图 3 所示,图 3(a)为原始图像,图 3(b)为处理结果。其灰度平均值为 123,灰度中值为 129,灰度标准差为 48.39。



下面讲解另一种用来判断图像是白天还是黑夜的方法,其基本步骤如下:


  • (1)读取原始图像,转换为灰度图,并获取图像的所有像素值;

  • (2)设置灰度阈值并计算该阈值以下的像素个数。比如像素的阈值设置为 50,统计低于 50 的像素值个数;

  • (3)设置比例参数,对比该参数与低于该阈值的像素占比,如果低于参数则预测为白天,高于参数则预测为黑夜。比如该参数设置为 0.8,像素的灰度值低于阈值 50 的个数占整幅图像所有像素个数的 90%,则认为该图像偏暗,故预测为黑夜;否则预测为白天。


具体实现的代码如下所示。


# -*- coding: utf-8 -*-# By:Eastmountimport cv2  import numpy as npimport matplotlib.pyplot as plt
#函数: 判断黑夜或白天def func_judge(img): #获取图像高度和宽度 height = grayImage.shape[0] width = grayImage.shape[1] piexs_sum = height * width dark_sum = 0 #偏暗像素个数 dark_prop = 0 #偏暗像素所占比例 for i in range(height): for j in range(width): if img[i, j] < 50: #阈值为50 dark_sum += 1
#计算比例 print(dark_sum) print(piexs_sum) dark_prop = dark_sum * 1.0 / piexs_sum if dark_prop >=0.8: print("This picture is dark!", dark_prop) else: print("This picture is bright!", dark_prop) #读取图像img = cv2.imread('day.png')
#转换为RGB图像img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#图像灰度转换grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#计算256灰度级的图像直方图hist = cv2.calcHist([grayImage], [0], None, [256], [0,255])
#判断黑夜或白天func_judge(grayImage)
#显示原始图像和绘制的直方图plt.subplot(121), plt.imshow(img_rgb, 'gray'), plt.axis('off'), plt.title("(a)")plt.subplot(122), plt.plot(hist, color='r'), plt.xlabel("x"), plt.ylabel("y"), plt.title("(b)")
plt.show()
复制代码


第一张测试图输出的结果如图 4 所示,其中图 4(a)为原始图像,图 4(b)为对应直方图曲线。



最终输出结果为“(‘This picture is bright!’, 0.010082704388303882)”,该预测为白天。



第二张测试图输出的结果如图 6 所示,其中图 6(a)为原始图像,图 6(b)为对应直方图曲线。



最终输出结果为“(‘This picture is dark!’, 0.8511824175824175)”,该预测为黑夜。


四.总结


本章主要讲解图像直方图相关知识点,包括掩膜直方图和 HS 直方图,并通过直方图判断黑夜与白天,通过案例分享直方图的实际应用。希望对您有所帮助,后续将进入图像增强相关知识点。


参考文献:


  • [1]冈萨雷斯. 数字图像处理(第 3 版)[M]. 北京:电子工业出版社, 2013.

  • [2]张恒博, 欧宗瑛. 一种基于色彩和灰度直方图的图像检索方法[J]. 计算机工程, 2004.

  • [3]Eastmount. [数字图像处理] 四.MFC 对话框绘制灰度直方图[EB/OL]. (2015-05-31). https://blog.csdn.net/eastmount/article/details/46237463.

  • [4]ZJE_ANDY. python3+opencv 利用灰度直方图来判断图片的亮暗情况[EB/OL]. (2018-06-20). https://blog.csdn.net/u014453898/article/details/80745987.

  • [5]阮秋琦. 数字图像处理学(第 3 版)[M]. 北京:电子工业出版社, 2008.

  • [6]Eastmount. [Python 图像处理] 十一.灰度直方图概念及 OpenCV 绘制直方图[EB/OL]. (2018-11-06). https://blog.csdn.net/Eastmount/article/details/83758402.


点击关注,第一时间了解华为云新鲜技术~

发布于: 刚刚阅读数: 2
用户头像

提供全面深入的云计算技术干货 2020-07-14 加入

生于云,长于云,让开发者成为决定性力量

评论

发布
暂无评论
Python从零到壹丨图像增强及运算:图像掩膜直方图和HS直方图_Python_华为云开发者联盟_InfoQ写作社区