您现在的位置是:首页 > 编程语言学习 > 前端编程语言 > 文章正文 前端编程语言

Python图像运算之图像掩膜直方图和HS直方图详解

2022-08-17 11:22:11 前端编程语言

简介这篇文章将为大家详细讲解图像掩膜直方图和HS直方图,并分享一个通过直方图判断白天与黑夜的案例。文中的示例代码讲解详细,感兴趣的小伙伴...

这篇文章将为大家详细讲解图像掩膜直方图和HS直方图,并分享一个通过直方图判断白天与黑夜的案例。文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下!

一.图像掩膜直方图

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

  1. # -*- coding: utf-8 -*- 
  2. # By:Eastmount 
  3. import cv2   
  4. import numpy as np 
  5. import matplotlib.pyplot as plt 
  6. import matplotlib 
  7.  
  8. #读取图像 
  9. img = cv2.imread('luo.png'
  10.  
  11. #转换为RGB图像 
  12. img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 
  13.  
  14. #设置掩膜 
  15. mask = np.zeros(img.shape[:2], np.uint8) 
  16. mask[100:300, 100:300] = 255 
  17. masked_img = cv2.bitwise_and(img, img, mask=mask) 
  18.  
  19. #图像直方图计算 
  20. hist_full = cv2.calcHist([img], [0], None, [256], [0,256]) #通道[0]-灰度图 
  21.  
  22. #图像直方图计算(含掩膜) 
  23. hist_mask = cv2.calcHist([img], [0], mask, [256], [0,256]) 
  24.  
  25. plt.figure(figsize=(8, 6)) 
  26.  
  27. #设置字体 
  28. matplotlib.rcParams['font.sans-serif']=['SimHei'
  29.  
  30. #原始图像 
  31. plt.subplot(221) 
  32. plt.imshow(img_rgb, 'gray'
  33. plt.axis('off'
  34. plt.title("(a)原始图像"
  35.  
  36. #绘制掩膜 
  37. plt.subplot(222) 
  38. plt.imshow(mask, 'gray'
  39. plt.axis('off'
  40. plt.title("(b)掩膜"
  41.  
  42. #绘制掩膜设置后的图像 
  43. plt.subplot(223) 
  44. plt.imshow(masked_img, 'gray'
  45. plt.axis('off'
  46. plt.title("(c)图像掩膜处理"
  47.  
  48. #绘制直方图 
  49. plt.subplot(224) 
  50. plt.plot(hist_full) 
  51. plt.plot(hist_mask) 
  52. plt.title("(d)直方图曲线"
  53. plt.xlabel("x"
  54. plt.ylabel("y"
  55. 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直方图。

  1. # -*- coding: utf-8 -*- 
  2. # By:Eastmount 
  3. import cv2   
  4. import numpy as np 
  5. import matplotlib.pyplot as plt 
  6.  
  7. #读取图像 
  8. img = cv2.imread('luo.png'
  9.  
  10. #转换为RGB图像 
  11. img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 
  12.  
  13. #图像HSV转换 
  14. hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) 
  15.  
  16. #计算H-S直方图 
  17. hist = cv2.calcHist(hsv, [0,1], None, [180,256], [0,180,0,256]) 
  18.  
  19. #原始图像 
  20. plt.figure(figsize=(8, 6)) 
  21. plt.subplot(121), plt.imshow(img_rgb, 'gray'), plt.title("(a)"), plt.axis('off'
  22.  
  23. #绘制H-S直方图 
  24. plt.subplot(122), plt.imshow(hist, interpolation='nearest'), plt.title("(b)"
  25. plt.xlabel("x"), plt.ylabel("y"
  26. plt.show() 

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

三.直方图判断白天黑夜

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

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

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

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

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

  1. # -*- coding: utf-8 -*- 
  2. # By:Eastmount 
  3. import cv2   
  4. import numpy as np 
  5. import matplotlib.pyplot as plt 
  6.  
  7. #函数: 获取图像的灰度平均值 
  8. def fun_mean(img, height, width): 
  9. sum_img = 0 
  10. for i in range(height): 
  11. for j in range(width): 
  12. sum_img = sum_img + int(img[i,j]) 
  13. mean = sum_img / (height * width) 
  14. return mean 
  15.  
  16. #函数: 获取中位数 
  17. def fun_median(data): 
  18. length = len(data) 
  19. data.sort() 
  20. if (length % 2)== 1:  
  21. z = length // 2 
  22. y = data[z] 
  23. else
  24. y = (int(data[length//2]) + int(data[length//2-1])) / 2 
  25. return y 
  26.  
  27. #读取图像 
  28. img = cv2.imread('lena-hd.png'
  29.  
  30. #图像灰度转换 
  31. grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 
  32.  
  33. #获取图像高度和宽度 
  34. height = grayImage.shape[0] 
  35. width = grayImage.shape[1] 
  36.  
  37. #计算图像的灰度平均值 
  38. mean = fun_mean(grayImage, height, width) 
  39. print("灰度平均值:", mean) 
  40.  
  41. #计算图像的灰度中位数 
  42. value = grayImage.ravel() #获取所有像素值 
  43. median = fun_median(value) 
  44. print("灰度中值:", median) 
  45.  
  46. #计算图像的灰度标准差 
  47. std = np.std(value, ddof = 1) 
  48. print("灰度标准差", std) 

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

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

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

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

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

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

  1. # -*- coding: utf-8 -*- 
  2. # By:Eastmount 
  3. import cv2   
  4. import numpy as np 
  5. import matplotlib.pyplot as plt 
  6.  
  7. #函数: 判断黑夜或白天 
  8. def func_judge(img): 
  9. #获取图像高度和宽度 
  10. height = grayImage.shape[0] 
  11. width = grayImage.shape[1] 
  12. piexs_sum = height * width 
  13. dark_sum = 0  #偏暗像素个数 
  14. dark_prop = 0 #偏暗像素所占比例 
  15.  
  16. for i in range(height): 
  17. for j in range(width): 
  18. if img[i, j] < 50: #阈值为50 
  19. dark_sum += 1 
  20.  
  21. #计算比例 
  22. print(dark_sum) 
  23. print(piexs_sum) 
  24. dark_prop = dark_sum * 1.0 / piexs_sum  
  25. if dark_prop >=0.8: 
  26. print("This picture is dark!", dark_prop) 
  27. else
  28. print("This picture is bright!", dark_prop) 
  29.     
  30. #读取图像 
  31. img = cv2.imread('day.png'
  32.  
  33. #转换为RGB图像 
  34. img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 
  35.  
  36. #图像灰度转换 
  37. grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 
  38.  
  39. #计算256灰度级的图像直方图 
  40. hist = cv2.calcHist([grayImage], [0], None, [256], [0,255]) 
  41.  
  42. #判断黑夜或白天 
  43. func_judge(grayImage) 
  44.  
  45. #显示原始图像和绘制的直方图 
  46. plt.subplot(121), plt.imshow(img_rgb, 'gray'), plt.axis('off'), plt.title("(a)"
  47. plt.subplot(122), plt.plot(hist, color='r'), plt.xlabel("x"), plt.ylabel("y"), plt.title("(b)"
  48.  
  49. 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直方图,并通过直方图判断黑夜与白天,通过案例分享直方图的实际应用。希望对您有所帮助,后续将进入图像增强相关知识点。

站点信息