(二)OpenCV-Python学习—对比度增强
·对于部分图像,会出现整体较暗或较亮的情况,这是由于图片的灰度值范围较小,即对比度低。实际应用中,通过绘制图片的灰度直方图,可以很明显的判断图片的灰度值分布,区分其对比度高低。对于对比度较低的图片,可以通过一定的算法来增强其对比度。常用的方法有线性变换,伽马变换,直方图均衡化,局部自适应直方图均衡化等。
1. 灰度直方图及绘制
灰度直方图用来描述每个像素在图像矩阵中出现的次数或概率。其横坐标一般为0-255个像素值,纵坐标为该像素值对应的像素点个数。如下图所示的图像矩阵(单通道灰度图,三通道时可以分别绘制),可以统计每个像素值出现的次数,也可以统计概率,统计像素值出现次数的灰度直方图如下所示。
灰度直方图绘制
a, 可以利用opencv的calcHist()统计像素值出现次数,通过matploblib的plot()绘制
b, 可以直接利用matploblib的hist()方法
cv2.calcHist()
参数:
img:输入图像,为列表,如[img]
channels: 计算的通道,为列表,如[]表示单通道,[,]统计两个通道
mask: 掩模,和输入图像大小一样的矩阵,为1的地方会进行统计(与图像逻辑与后再统计);无掩模时为None
histSize: 每一个channel对应的bins个数,为列表,如[]表示256个像素值
ranges: bins的边界,为列表,如[,]表示像素值范围在0-256之间
accumulate: Accumulation flag. If it is set, the histogram is not cleared in the beginning when it is allocated. This feature enables you to compute a single histogram from several sets of arrays, or to update the histogram in time.
如下图所示,分别绘制了灰度分布曲线图,灰度分布直方图和两者叠加图形,代码如下:
#coding:utf- import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np img = cv.imread(r"C:\Users\Administrator\Desktop\maze.png",) hist = cv.calcHist([img],[],None,[],[,]) plt.subplot(,,),plt.plot(hist,color="r"),plt.axis([,,,np.max(hist)])
plt.xlabel("gray level")
plt.ylabel("number of pixels") plt.subplot(,,),plt.hist(img.ravel(),bins=,range=[,]),plt.xlim([,])
plt.xlabel("gray level")
plt.ylabel("number of pixels") plt.subplot(,,)
plt.plot(hist,color="r"),plt.axis([,,,np.max(hist)])
plt.hist(img.ravel(),bins=,range=[,]),plt.xlim([,])
plt.xlabel("gray level")
plt.ylabel("number of pixels") plt.show()
c.通过np.histogram()和plt.hist()也可以计算出灰度值分布
#coding:utf- import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np img = cv.imread(r"C:\Users\Administrator\Desktop\maze.png",)
histogram,bins = np.histogram(img,bins=,range=[,])
print(histogram)
plt.plot(histogram,color="g")
plt.axis([,,,np.max(histogram)])
plt.xlabel("gray level")
plt.ylabel("number of pixels")
plt.show()
np.histogram()
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np img = cv.imread(r"C:\Users\Administrator\Desktop\maze.png",)
rows,cols = img.shape
hist = img.reshape(rows*cols)
histogram,bins,patch = plt.hist(hist,,facecolor="green",histtype="bar") #histogram即为统计出的灰度值分布
plt.xlabel("gray level")
plt.ylabel("number of pixels")
plt.axis([,,,np.max(histogram)])
plt.show()
plt.hist()
2. 对比度增强
对比度增强,即将图片的灰度范围拉宽,如图片灰度分布范围在[50,150]之间,将其范围拉升到[0,256]之间。这里介绍下 线性变换,直方图正规化,伽马变换,全局直方图均衡化,限制对比度自适应直方图均衡化等算法。
2.1 线性变换
通过函数y=ax+b对灰度值进行处理,例如对于过暗的图片,其灰度分布在[0,100], 选择a=2,b=10能将灰度范围拉伸到[10, 210]。可以通过np或者opencv的convertScaleAbs()函数来实现,对应参数列表如下:
cv2.convertScaleAbs(src,alpha,beta)
src: 图像对象矩阵
dst:输出图像矩阵
alpha:y=ax+b中的a值
beta:y=ax+b中的b值
(对于计算后大于255的像素值会截断为255)
使用示例代码和效果图如下:
#coding:utf- import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np img = cv.imread(r"C:\Users\Administrator\Desktop\dark.jpg")
print(img)
img_bright = cv.convertScaleAbs(img,alpha=1.5,beta=)
print(img_bright) cv.imshow("img",img)
cv.imshow("img_bright",img_bright)
cv.waitKey()
cv.destroyAllWindows()
convertScaleAbs()
#coding:utf- import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np img = cv.imread(r"C:\Users\Administrator\Desktop\dark.jpg")
a=1.5
b=
y = np.float(a)*img+b
y[y>]=
y = np.round(y)
img_bright= y.astype(np.uint8) cv.imshow("img",img)
cv.imshow("img_bright",img_bright)
cv.waitKey()
cv.destroyAllWindows()
numpy实现
(实用性:numpy自定义实现时,可以针对不同区间像素点,采用不同系数a,b来动态改变像素值)
2.2 直方图正规化
对于上述线性变换,系数a,b需要自己摸索设置。直方图正规化的系数固定,一般将原图片的像素值范围映射到[0,255]范围内。假设原图片的像素值分布范围为Input:[min, max], 映射后的范围为Output:[0,255], 则对应的系数a=(255-0)/(max-min), 系数b=0。即计算公式:
opencv提供了normalize()函数来实现灰度正规化,对应参数列表如下:
cv2.normalize(src,dst,alpha,beta,normType,dtype,mask)
参数:
src: 图像对象矩阵
dst:输出图像矩阵(和src的shape一样)
alpha:正规化的值,如果是范围值,为范围的下限 (alpha – norm value to normalize to or the lower range boundary in case of the range normalization.)
beta:如果是范围值,为范围的上限;正规化中不用到 ( upper range boundary in case of the range normalization; it is not used for the norm normalization.)
norm_type:normalize的类型
cv2.NORM_L1:将像素矩阵的1-范数做为最大值(矩阵中值的绝对值的和)
cv2.NORM_L2:将像素矩阵的2-范数做为最大值(矩阵中值的平方和的开方)
cv2.NORM_MINMAX:将像素矩阵的∞-范数做为最大值 (矩阵中值的绝对值的最大值) dtype: 输出图像矩阵的数据类型,默认为-,即和src一样
mask:掩模矩阵,只对感兴趣的地方归一化
(对于alpha的值,不是很清楚含义,经过试验,应该是一个锚点,用像素矩阵中的范数计算出来的比例和alpha相乘,当dtype为cv2.NORM_MINMAX时,其计算公式类似如下:
使用示例代码和效果图如下:
#coding:utf- import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np img = cv.imread(r"C:\Users\Administrator\Desktop\dark.jpg")
img_norm=cv.normalize(img,dst=None,alpha=,beta=,norm_type=cv.NORM_MINMAX)
cv.imshow("img",img)
cv.imshow("img_norm",img_norm)
cv.waitKey()
cv.destroyAllWindows()
cv.normalize()
#coding:utf- import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np img = cv.imread(r"C:\Users\Administrator\Desktop\dark.jpg")
out_min=
out_max= in_min = np.min(img)
in_max = np.max(img) a=float(out_max-out_min)/(in_max-in_min)
b=out_min-a*in_min
img_norm = img*a+b
img_norm = img_norm.astype(np.uint8)
cv.imshow("img",img)
cv.imshow("img_norm",img_norm)
cv.waitKey()
cv.destroyAllWindows()
numpy实现类似normalize
2.3 伽马变换
将输入图像的像素值除以255,归一化到[0,1]区间,然后计算其γ次方值,用公式表示如下,其中I(r,c)为归一化后的像素值,当γ=1时原像素值不影响,当0<γ<1时,增大像素值,提高图片对比度;反之γ>1时能降低图片对比度。
实现代码和示例如下:
#coding:utf- import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np img = cv.imread(r"C:\Users\Administrator\Desktop\dark.jpg")
img_norm = img/255.0 #注意255.0得采用浮点数
img_gamma = np.power(img_norm,0.4)*255.0
img_gamma = img_gamma.astype(np.uint8) cv.imshow("img",img)
cv.imshow("img_gamma",img_gamma)
cv.waitKey()
cv.destroyAllWindows()
numpy实现伽马变换
2.4 全局直方图均衡化
直方图均衡化的目的是将原图片每个像素值的像素点个数进行重新分配到[0,255]的256个像素值上,使得每个像素值对应的像素点个数近似相等,即重新分配后,0-255的每个像素值对应的像素点个数近似为(rows*cols/256),(直方图均衡化对应的数学原理参考:https://blog.csdn.net/superjunenaruto/article/details/52431941)。opencv里面equalizeHist()函数实现了相应的功能,只能处理单通道数据,参数列表如下:
cv2.equalizeHist(src,dst)
src: 图像对象矩阵,必须为单通道的uint8类型的矩阵数据
dst:输出图像矩阵(和src的shape一样)
实现代码和示例如下:
#coding:utf- import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
import math img = cv.imread(r"C:\Users\Administrator\Desktop\dark.jpg",)
img_equalize = cv.equalizeHist(img)
cv.imshow("img",img)
cv.imshow("img_equalize",img_equalize)
cv.waitKey()
cv.destroyAllWindows()
opencv equalizeHist()
#coding:utf- import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
import math #统计灰度分布
def calc_hist(img):
rows,cols = img.shape[:]
hist=np.zeros(,np.uint64) #注意此处的数据格式不要用np.uint8,会溢出但不报错
for r in range(rows):
for c in range(cols):
hist[img[r,c]]+= return hist def equalize_hist(img):
rows,cols = img.shape[:]
hist = calc_hist(img) #计算灰度累积分布
hist_sum=np.zeros([],np.uint32) #注意数据类型为np.uint32,防止溢出
for i in range():
if i==:
hist_sum[i]=hist[i]
else:
hist_sum[i] = hist[i]+hist_sum[i-] #输出图像的灰度分布
output_hist = np.zeros(,np.uint8)
cofficient= 256.0/(rows*cols)
for i in range():
q = cofficient*float(hist_sum[i])-
if q>=:
output_hist[i]=math.floor(q)
else:
output_hist[i]= #输出图像的像素值
output_img=np.zeros([rows,cols],np.uint8)
for r in range(rows):
for c in range(cols):
output_img[r,c]=output_hist[img[r,c]] return output_img if __name__=="__main__":
img = cv.imread(r"C:\Users\Administrator\Desktop\dark.jpg",)
img_equalize=equalize_hist(img)
cv.imshow("img",img)
cv.imshow("img_equalize",img_equalize)
cv.waitKey()
cv.destroyAllWindows()
使用numpy实现equalizeHist
(通过numpy实现equalizeHist的算法思路参见直方图均衡化的数学原理,这里没写出。。。。。)
2.5 限制对比度自适应直方图均衡化
相比全局直方图均衡化,自适应直方图均衡化将图像划分为不重叠的小块,在每一小块进行直方图均衡化,但若小块内有噪声,影响很大,需要通过限制对比度来进行抑制,即限制对比度自适应直方图均衡化。如果限制对比度的阈值设置会40,在局部直方图分布中某个像素值出现次数为45,那么多出的5次像素点会被去掉,平均成其他像素值,如图所示:
opencv通过createCLAHE()和apply()函数来实现,其对应参数如下:
clahe=cv2.createCLAHE(clipLimit,tileGridSize)
clipLimit:限制对比度的阈值,默认为40,直方图中像素值出现次数大于该阈值,多余的次数会被重新分配
tileGridSize:图像会被划分的size, 如tileGridSize=(,),默认为(,) calhe.apply(img) #对img进行限制对比度自适应直方图均衡化
代码示例和效果如下:(实际使用中可以先去噪声,再进行对比度增强)
#coding:utf- import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
import math img = cv.imread(r"C:\Users\Administrator\Desktop\dark.jpg",)
clahe = cv.createCLAHE(,(,))
dst = clahe.apply(img)
cv.imshow("img",img)
cv.imshow("dst",dst)
cv.waitKey()
cv.destroyAllWindows()
createCLAHE()
参考:
官方文档:https://www.docs.opencv.org/4.1.0/
(二)OpenCV-Python学习—对比度增强的更多相关文章
- 二、python学习-函数
类型判断 1.type()直接获取类型 2.isinstance 用法一:isinstance(值,类型) 返回真或假 用法二:isinstance(值,(类型1,类型2 ...)) 有一个类型满足 ...
- (二)Python 学习第二天--爬5068动漫图库小案例
(注:代码和网站仅仅是学习用途,非营利行为,源代码参考网上大神代码,仅仅用来学习
- python入门灵魂5问--python学习路线,python教程,python学哪些,python怎么学,python学到什么程度
一.python入门简介 对于刚接触python编程或者想学习python自动化的人来说,基本都会有以下python入门灵魂5问--python学习路线,python教程,python学哪些,pyth ...
- OpenCV之Python学习笔记
OpenCV之Python学习笔记 直都在用Python+OpenCV做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书< ...
- Python学习(二)Python 简介
Python 简介 官方指南及文档 Python2.7官方指南(中文版):http://pan.baidu.com/s/1dDm18xr Python3.4官方指南(中文版):http://pan.b ...
- python学习_数据处理编程实例(二)
在上一节python学习_数据处理编程实例(二)的基础上数据发生了变化,文件中除了学生的成绩外,新增了学生姓名和出生年月的信息,因此将要成变成:分别根据姓名输出每个学生的无重复的前三个最好成绩和出生年 ...
- 【Python学习笔记之二】浅谈Python的yield用法
在上篇[Python学习笔记之一]Python关键字及其总结中我提到了yield,本篇文章我将会重点说明yield的用法 在介绍yield前有必要先说明下Python中的迭代器(iterator)和生 ...
- Python学习二:词典基础详解
作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/7862377.html 邮箱:moyi@moyib ...
- python3.4学习笔记(二十三) Python调用淘宝IP库获取IP归属地返回省市运营商实例代码
python3.4学习笔记(二十三) Python调用淘宝IP库获取IP归属地返回省市运营商实例代码 淘宝IP地址库 http://ip.taobao.com/目前提供的服务包括:1. 根据用户提供的 ...
随机推荐
- 在windows上搭建hadoop开发环境
下载hadoop: http://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common 点击下面链接进行下载 然后进行解压 如果解压出现下面的情况 则用管 ...
- plsql连接数据库后备注乱码|plsql连接数据库后中文乱码
-- 背景:连接开发库后查阅单表备注信息时发现所有的备注都显示为"???????". -- 解决方案: -- (1). 首先先确认数据库的编码格式字符集,查询数据库编码格式. -- ...
- Mysql5.7 建表报 [Err] 1055 问题
最近,在win10系统上,使用docker下载了 mysql5.7镜像,然后建表时,发生奇怪的问题,表正常创建,但底部会出现一行错误信息,如下: [Err] 1055 - Expression #1 ...
- Linux指令(文件目录类)
pwd 显示当前工作目录的绝对路径 ls [选项] [目录或是文件] 常用选项 -a 显示当前目录所有的文件和目录,包括隐藏的 -l 以列表的方式显示信息 cd [参数] (功能描述:切换到指定目录) ...
- centos下安装opencv
根据项目需要,安装opencv并提供给开发使用,并且使用opencv提供python3的API接口.虽然不知道是个啥,还是简单了解下. opencv是什么? OpenCV的全称是Open Source ...
- windows10 进入BIOS
windows10开机进入不了BIOS 原因 上网查了电脑固件所应该有的进入键,什么F1.F2.F12.Delete以及什么要配置Fn+F1...等等方法就是开机进入不了BIOS. 解决办法 最后发现 ...
- Linux加密和数据安全性
加密和安全 墨菲定律 墨菲定律:一种心理学效应,是由爱德华·墨菲(Edward A. Murphy)提出的, 原话:如果有两种或两种以上的方式去做某件事情,而其中一种选择方式将导 致灾难,则必定有人会 ...
- 介于JAVAswing和Socket写的聊天室
在厦门的第一阶段给我们复习了JAVASE基础,第一阶段的小玩具叫我们自选题材,我自己选了聊天室这个内容,这个小玩具无论是线程,还是网络编程,都会涉及到,比较有综合性,所以我选了这个: 这是我的包体结构 ...
- Nginx基于域名的虚拟主机
一.基于域名的虚拟主机 修改配置文件/usr/local/nginx/conf/nginx.conf 创建新的虚拟主机的根目录和默认网页index.html 重新加载nginx的配置文件 查看两个虚拟 ...
- P2606 [ZJOI2010]排列计数
P2606 [ZJOI2010]排列计数 因为每个结点至多有一个前驱,所以我们可以发现这是一个二叉树.现在我们要求的就是以1为根的二叉树中,有多少种情况,满足小根堆的性质. 设\(f(i)\)表示以\ ...