摘要:本章主要讲解图像直方图相关知识点,包括掩膜直方图和HS直方图,并通过直方图判断黑夜与白天,通过案例分享直方图的实际应用。

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

一.图像掩膜直方图

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

# -*- coding: utf-8 -*-
# By:Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt
import 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] = 255
masked_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:Eastmount
import cv2
import numpy as np
import 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:Eastmount
import cv2
import numpy as np
import 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:Eastmount
import cv2
import numpy as np
import 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.

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

Python从零到壹丨图像增强及运算:图像掩膜直方图和HS直方图的更多相关文章

  1. [Python] 文科生零基础学编程系列二——数据类型、变量、常量的基础概念

    上一篇:[Python] 文科生零基础学编程系列--对象.集合.属性.方法的基本定义 下一篇: (仍先以最简单的Excel的VBA为例,语法与Python不同,但概念和逻辑需要理解透彻) p.p1 { ...

  2. [Python] 文科生零基础学编程系列三——数据运算符的基本类别

    上一篇:[Python] 文科生零基础学编程系列二--数据类型.变量.常量的基础概念 下一篇: ※ 程序的执行过程,就是对数据进行运算的过程. 不同的数据类型,可以进行不同的运算, 按照数据运算类型的 ...

  3. 知了课堂 Python Flask零基础 笔记整理

    目录 起步 安装Python2.7: Python虚拟环境介绍与安装: pip安装flask: 认识url: URL详解 web服务器和应用服务器以及web应用框架: Flask 第一个flask程序 ...

  4. gitbook 入门教程之从零到壹发布自己的插件

    什么是插件 Gitbook 插件是扩展 Gitbook 功能的最佳方式,如果 Gitbook 没有想要的功能或者说网络上也没有现成的解决方案时,那么只剩下自食其力这条道路,让我们一起来自力更生开发插件 ...

  5. IRIS数据集的分析-数据挖掘和python入门-零门槛

    所有内容都在python源码和注释里,可运行! ########################### #说明: # 撰写本文的原因是,笔者在研究博文“http://python.jobbole.co ...

  6. 如何从Python负零基础到精通数据分析

    一.为什么学习数据分析 1.运营的尴尬:运营人需要一个硬技能每个初入行的新人都会察觉到,运营是一个似乎并没有自己的核心竞争力和安全感的工作.因为每天的工作好像都被各种琐事所围绕,而只有一个主题是永恒不 ...

  7. 一凡老师亲录视频,Python从零基础到高级进阶带你飞

    如需Q群交流 群:893694563 不定时更新2-3节视频 零基础学生请点击 Python基础入门视频 如果你刚初入测试行业 如果你刚转入到测试行业 如果你想学习Python,学习自动化,搭建自动化 ...

  8. Python图像处理丨三种实现图像形态学转化运算模式

    摘要:本篇文章主要讲解Python调用OpenCV实现图像形态学转化,包括图像开运算.图像闭运算和梯度运算 本文分享自华为云社区<[Python图像处理] 九.形态学之图像开运算.闭运算.梯度运 ...

  9. Python 从零学起(纯基础) 笔记 之 迭代器、生成器和修饰器

    Python的迭代器. 生成器和修饰器 1. 迭代器是访问集合元素的一种方式,从第一个到最后,只许前进不许后退. 优点:不要求事先准备好整个迭代过程中的所有元素,仅仅在迭代到某个元素时才计算该元素,而 ...

  10. Python 从零学起(纯基础) 笔记 之 深浅拷贝

    深浅拷贝 1. import  copy#浅拷贝copy.copy()#深拷贝copy.deepcopy()#赋值 = 2.   对于数字和字符串而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个 ...

随机推荐

  1. 【原创】i.MXRT J-Flash烧写算法使能eFuse熔丝位写入

    ​       临近年底,终于又憋了一篇文章出来,本来年初的时候是有计划把去年总结的一些东西整理下发布出来的,结果还是被工作和生活上各种琐事给耽搁了.哎,今年刚过了自己35岁的生日,眼瞅着这个人生节点 ...

  2. 鹅长微服务发现与治理巨作PolarisMesh实践-上

    @ 目录 概述 定义 核心功能 组件和生态 特色亮点 解决哪些问题 官方性能数据 架构原理 资源模型 服务治理 基本原理 服务注册 服务发现 安装 部署架构 集群安装 SpringCloud应用接入 ...

  3. ubuntu+Django + nginx + uwsgi 部署

    ubuntu+Django + nginx + uwsgi 部署 0.前期准备 注意:以下几件事都必须在激活虚拟环境下完成 运行以下命令生成项目所需的依赖列表,会在项目根目录生成一个requireme ...

  4. 有依赖的背包问题(Acwing 10)

    1 # include<iostream> 2 # include<cstring> 3 # include<algorithm> 4 using namespac ...

  5. android 代码分析

    1.@Override注解 @Override 注解是用来指定方法重写的,只能修饰方法并且只能用于方法重写,不能修饰其它的元素. 作用是告诉编译器检查这个方法,保证父类要包含一个被该方法重写的方法,否 ...

  6. Oracle中新建数据表的两种方法

    首发微信公众号:SQL数据库运维 原文链接:https://mp.weixin.qq.com/s?__biz=MzI1NTQyNzg3MQ==&mid=2247485212&idx=1 ...

  7. Go语言核心36讲24

    你好,我是郝林,今天我们继续来聊聊panic函数.recover函数以及defer语句的内容. 我在前一篇文章提到过这样一个说法,panic之中可以包含一个值,用于简要解释引发此panic的原因. 如 ...

  8. 第2-3-6章 打包批量下载附件的接口开发-文件存储服务系统-nginx/fastDFS/minio/阿里云oss/七牛云oss

    目录 5.6 接口开发-根据文件id打包下载附件 5.6.1 接口文档 5.6.2 代码实现 5.6.3 接口测试 5.7 接口开发-根据业务类型/业务id打包下载 5.7.1 接口文档 5.7.2 ...

  9. 第2-3-8章 分片上传和分片合并的接口开发-文件存储服务系统-nginx/fastDFS/minio/阿里云oss/七牛云oss

    目录 5.10 接口开发-分片上传 5.10.1 分片上传介绍 5.10.2 前端分片上传插件webuploader 5.10.3 后端代码实现 5.10.3.1 接口文档 5.10.3.2 代码开发 ...

  10. WebApi如何启用Session并且使用

    首先打开项目的Global.asax文件,重新方法init public override void Init() { //注册事件 this.AuthenticateRequest += WebAp ...