(自己编写函数)Python+opencv 计算并绘制灰度图和彩色图的直方图并进行均衡化操作
最终效果(完整代码在最后):
图片的直方图

原图:

均衡化后的图片:

什么是灰度直方图?
灰度直方图(histogram)是灰度级的函数,描述的是图像中每种灰度级像素的个数,反映图像中每种灰度出现的频率。横坐标是灰度级,纵坐标是灰度级出现的频率。
对于连续图像,平滑地从中心的高灰度级变化到边缘的低灰度级。直方图定义为:
其中A(D)为阈值面积函数:为一幅连续图像中被具有灰度级D的所有轮廓线所包围的面积。对于离散函数,固定ΔD为1,则:H(D)=A(D)-A(D+1)
色彩直方图是高维直方图的特例,它统计色彩的出现频率,即色彩概率分布信息。
通常这需要一定的量化过程,将色彩分成若干互不重叠的种类。一般不直接在RGB色彩空间中统计,而是在将亮度分离出来后,对代表色彩部分的信息进行统计,如在HSI空间的HS子空间、YUV空间的UV子空间,以及其它反映人类视觉特点的彩色空间表示中进行。
其中直方图的计算方法如下:
依据定义,若图像具有L(通常L=256,即8位灰度级)级灰度,则大小为MxN的灰度图像f(x,y)的灰度直方图hist[0…L-1]可用如下计算获得。
1、初始化 hist[k]=0; k=0,…,L-1
2、统计 hist[f(x,y)]++; x=0,…,M-1, y =0,…,N-1
3、归一化 hist[f(x,y)]/=M*N
那么说了这么多,直方图究竟有什么作用呢?
在使用轮廓线确定物体边界时,通过直方图更好的选择边界阈值,进行阈值化处理;对物体与背景有较强对比的景物的分割特别有用;简单物体的面积和综合光密度IOD可以通过图像的直方图求得。
一幅图像由不同灰度值的像素组成,图像中灰度的分布情况是该图像的一个重要特征。图像的灰度直方图就描述了图像中灰度分布情况,能够很直观的展示出图像中各个灰度级所占的多少。
图像的灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数:其中,横坐标是灰度级,纵坐标是该灰度级出现的频率。打个比方就是 这张图中属于255这个灰度级,那么整张图片中255出现的次数就是255出现的频率。
要实现绘制直方图首先需要每个图片中每个灰度级出现的次数读取出来。
这个用到的是 opencv 中的自带的函数cv2.imread(filepath),读取出来的数据是一个 numpy.ndarray 的矩阵,其中就是每个灰度级出现的次数。

之后,我们要做的就是将每个灰度级出现的次数统计出来,这里我使用了一个循环遍历然后通过 count 来数出每个灰度级出现的次数。之后读取出来以后就是类似于一个字典的形式,前面的key是灰度级,后面的value就是这个灰度级出现的次数。
注意:因为一张图片不一定包含 0-255 所有的灰度级,所以需要再次设置一个从 0-256 的循环来进行遍历,没有的将这个灰度级也加入,并将他的 value 设置为0
#计算灰度图的直方图
def clczhifangtu(gray) :
hist_new = []
num = []
hist_result = []
hist_key = []
gray1 = list(gray.ravel()) #将读取出来的数组转化为一维列表方便循环遍历
obj = dict(collections.Counter(gray1)) #计算每个灰度级出现的次数
obj = sorted(obj.items(),key=lambda item:item[0])
for each in obj :
hist1 = []
key = list(each)[0]
each =list(each)[1]
hist_key.append(key)
hist1.append(each)
hist_new.append(hist1)
#检查从0-255每个通道是否都有个数,没有的话添加并将值设为0
for i in range (0,256) :
if i in hist_key :
num = hist_key.index(i)
hist_result.append(hist_new[num])
else :
hist_result.append([0])
if len(hist_result) < 256 : #检查循环后的列表中是不是已经包含所有的灰度级
for i in range (0,256-len(hist_result)) :
hist_new.append([0])
hist_result = np.array(hist_result)
return hist_result
计算均衡化的的原理就不细说了,直接上代码
#计算均衡化
def clcresult(hist_new ,lut ,gray) :
sum = 0
Value_sum = []
hist1 = []
binValue = []
for hist1 in hist_new :
for j in hist1:
binValue.append(j)
sum += j
Value_sum.append(sum)
min_n = min(Value_sum)
max_num = max(Value_sum)
# 生成查找表
for i, v in enumerate(lut):
lut[i] = int(254.0 * Value_sum[i] / max_num + 0.5)
# 计算
result = lut[gray]
return result
灰度图处理代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
import collections
#计算灰度图的直方图
def clczhifangtu(gray) :
hist_new = []
num = []
hist_result = []
hist_key = []
gray1 = list(gray.ravel())
obj = dict(collections.Counter(gray1))
obj = sorted(obj.items(),key=lambda item:item[0])
for each in obj :
hist1 = []
key = list(each)[0]
each =list(each)[1]
hist_key.append(key)
hist1.append(each)
hist_new.append(hist1)
#检查从0-255每个通道是否都有个数,没有的话添加并将值设为0
for i in range (0,256) :
if i in hist_key :
num = hist_key.index(i)
hist_result.append(hist_new[num])
else :
hist_result.append([0])
if len(hist_result) < 256 :
for i in range (0,256-len(hist_result)) :
hist_new.append([0])
hist_result = np.array(hist_result)
return hist_result
#计算均衡化
def clcresult(hist_new ,lut ,gray) :
sum = 0
Value_sum = []
hist1 = []
binValue = []
for hist1 in hist_new :
for j in hist1:
binValue.append(j)
sum += j
Value_sum.append(sum)
min_n = min(Value_sum)
max_num = max(Value_sum)
# 生成查找表
for i, v in enumerate(lut):
lut[i] = int(254.0 * Value_sum[i] / max_num + 0.5)
# 计算
result = lut[gray]
return result
def main() :
image = cv2.imread(r'D:\Code\Python\1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 创建空的查找表
lut = np.zeros(256, dtype=gray.dtype)
#直方图转化
hist_new = clczhifangtu(gray)
#并绘制直方图
plt.plot(hist_new)
plt.show()
result = clcresult(hist_new,lut,gray)
cv2.imshow('yuantu',gray)
cv2.imshow("Result",result)
cv2.waitKey(0)
cv2.destroyAllWindows()
main()
彩色图和灰度图处理类似,不过要把彩色图的三个通道分开单独处理,之后在合并即可
import cv2
import numpy as np
import matplotlib.pyplot as plt
import collections
def clczhifangtu(gray):
# 计算彩色图单通道的直方图
hist_new = []
num = []
hist_result = []
hist_key = []
gray1 = list(gray.ravel())
obj = dict(collections.Counter(gray1))
obj = sorted(obj.items(),key=lambda item:item[0])
for each in obj :
hist1 = []
key = list(each)[0]
each =list(each)[1]
hist_key.append(key)
hist1.append(each)
hist_new.append(hist1)
for i in range (0,256) :
if i in hist_key :
num = hist_key.index(i)
hist_result.append(hist_new[num])
else :
hist_result.append([0])
if len(hist_result) < 256 :
for i in range (0,256-len(hist_result)) :
hist_new.append([0])
hist_result = np.array(hist_result)
return hist_result
#单通道均衡化
def clcresult(hist_new, lut, gray):
sum = 0
Value_sum = []
hist1 = []
binValue = []
for hist1 in hist_new:
for j in hist1:
binValue.append(j)
sum += j
Value_sum.append(sum)
min_n = min(Value_sum)
max_num = max(Value_sum)
# 生成查找表
for i, v in enumerate(lut):
lut[i] = int(254.0 * Value_sum[i] / max_num + 0.5)
# 计算
result = lut[gray]
return result
#获取红色通道:
def get_red(img):
redImg = img[:, :, 2]
return redImg
#获取绿色通道:
def get_green(img):
greenImg = img[:, :, 1]
return greenImg
#获取蓝色通道
def get_blue(img):
blueImg = img[:, :, 0]
return blueImg
def main():
image = cv2.imread(r'D:\Code\Python\2.jpg')
# 创建空的查找表
lut = np.zeros(256, dtype=image.dtype)
b = get_blue(image)
g = get_green(image)
r = get_red(image)
hist_new_b = clczhifangtu(b)
hist_new_g = clczhifangtu(g)
hist_new_r = clczhifangtu(r)
#绘制直方图
plt.plot(hist_new_b, color='b')
plt.plot(hist_new_g, color='g')
plt.plot(hist_new_r, color='r')
plt.show()
result_b = clcresult(hist_new_b, lut, b)
result_g = clcresult(hist_new_g, lut, g)
result_r = clcresult(hist_new_r, lut, r)
#合并通道
result = cv2.merge((result_b, result_g, result_r))
cv2.imshow('yuantu', image)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
main()

原图

均衡化后

智能推荐
【OpenCV3经典编程100例】(21)直方图处理:计算和绘制灰度图像的一维直方图、calcHist()函数
直方图是图像十分重要的特征,,是对数据进行统计的一种方法!直方图处理在数字图像处理中占着举足轻重的地位。 首先,我们利用calcHist()函数计算灰度图像的直方图,即统计灰度图中像素的灰度值0到255出现的次数。 然后绘制一维直方图,观察直方图我们可以得到很多关于图像特征的信息。 API函数: 一、c++示例代码 二、运行截图 1.灰度原图 2.一维直方图...
Kinect 获取深度图计算距离,并进行彩色图和深度图之间的映射
Kinect 获取深度图计算距离,并进行彩色图和深度图之间的映射 最近所进行的项目需要利用KINECT获取深度距离,需要得到彩色图中某一点的位置,在网上找了很多资料,都不是很好,碰了很多坑,这里我整理了一下发给大家,大家有需求可以自取。 获取深度图计算距离 KINECT安装openCv安装这里就不说了呢,网上一大堆。 直接上代码: 注意这里是初始化的一些代码,有些头文件是之后做通信用的,不需要的话...
灰度图的直方图均衡化的原理及实现
直方图均衡化的作用是图像增强。 有两个问题比较难懂,一是为什么要选用累积分布函数,二是为什么使用累积分布函数处理后像素值会均匀分布。 第一个问题。均衡化过程中,必须要保证两个条件:①像素无论怎么映射,一定要保证原来的大小关系不变,较亮的区域,依旧是较亮的,较暗依旧暗,只是对比度增大,绝对不能明暗颠倒; ②如果是八位图像,那么像素映射函数的值域应在0和255之间的,不能越界。综合以上两个条件,累积分...
如何编写自己的python包,并进行安装和发布
如何编写自己的python包,并进行安装 1.新建一个文件夹My_pkgs,在该文件夹里再新建一个文价夹my_packages和一个文本文件setup.txt 2.在my_packages文件夹里新建三个txt文件,分别为:__ init__.py;getMax.txt;getMin.txt 结果如下图: 如果不进行安装,则不需要新建setup.txt。 Python中_init_.py是pack...
冒泡排序,及改进方式,性能优化400%>>>附图解加源码
首先源码附上,源码中带有注释,看不懂没关系,源码后面附带图解,最后附上代码效率提升图 源码如下: 方案一:其实实现很简单,两层循环,每次内层迭代出最大的一个值,将其放入数组最后一个位置,外层循环的末端便往前移一位。其原理如下图 方案一代码块: 方案二:优化改进 仔细观察上面的图,我们不难发现当迭代到图下这样的情况时,其实已经全排序好了,但是我们还是需要对它进行1,2,3,4,5,6的迭代,这些情况...
猜你喜欢
css3常用选择器
先介绍一下基本选择器,如下几种 *:通配符。选择页面的所有元素 E:元素选择器。对页面的一些元素进行选择,如p,div,li等 .class:类选择器 #id:id选择器。一个Id在一个页面中只能选择,这是和类选择器的区别 E F:后代选择器。如ul li。选中ul下的li E>F:子元素选择器。如下,可以用 h1 > strong {color:red;}使h1的子元素strong变...
python is not set from command line or npm configuration
问题 猜测原因 python版本冲突 解决方案 去官网找到最新版本python 点击下载,注意记住你下载的目录,下载好以后,打开这个目录下的文件夹,Python310, 整个文件夹复制一下 在项目里运行npm config list --json 找到python的路径 我的是 C:\\Python27\\python.exe 说明项目里用的还是py...
Java8 Stream流操作
前言 我们常常需要将一个容器转化成另一个容器,或是对这个容器中的数据进行批量处理,这时使用Stream流可以大大减少我们的工作量。 1 Stream概述 Java 8 是一个非常成功的版本,这个版本新增的Stream,配合同版本出现的 Lambda ,给我们操作集合(Collection)提供了极大的便利。 那么什么是Stream? Stream将要处理的元素集合看作一种流,在流的过程中,借助St...
带你玩转Visual Studio——带你跳出坑爹的Runtime Library坑
在Windows下进行C++的开发,不可避免的要与Windows的底层库进行交互,然而VS下的一项设置MT、MTd、MD和MDd却经常让人搞迷糊,相信不少人都被他坑过,特别是你工程使用了很多第三库的时候,及容易出现各种链接问题。看一下下面这个错误提示: LIBCMT.lib(_file.obj) : error LNK2005: ___initstdio already defined...
git 设置 gitignore 忽略 __pycache__
清除git缓存中的pycache 直接删掉硬盘上的文件 如果我想保留硬盘上的这个文件,而只删除版本管理中的文件,就需要加入--cached参数。 切换分支出现问题 尽管我已经删除了__pycache__,硬盘也没有了,但是切换分支的时候依然是会提示本地重写的情况。 提示:需要我在切换分支之前,提交一次更新。 提交了更新之后,再来尝试切换分支,如下: 成功了,说明当做了任何变更之后,切换分支前需要执...
