- 本系列python版本:python3.5.4
- 本系列opencv-python版本:opencv-python3.4.2.17
- 本系列使用的开发环境是jupyter notebook,是一个python的交互式开发环境,测试十分方便,并集成了vim操作,安装教程可参考:windows上jupyter notebook主题背景、字体及扩展插件配置(集成vim环境)
在上文【数字图像处理系列一】opencv-python快速入门篇 中结合了opencv-python对数字图像的基本操作有了一定的了解,本文我们将一起过数字图像概念和形成原理,并探讨一下亮度、对比度、分辨率、饱和度、锐化等基本属性
对于一幅图像,我们可以将其放入坐标系中,这里取图像左上定点为坐标原点,x 轴向右,和笛卡尔坐标系x轴相同;y 轴向下,和笛卡尔坐标系y轴相反。这样我们可将一幅图像定义为一个二维函数 f(x,y),图像中的每个像素就可以用 (x,y) 坐标表示,而在任何一对空间坐标 (x,y) 处的幅值 f 称为图像在该点的强度或灰度,当 x,y 和灰度值 f 是有限离散数值时,便称该图像为 数字图像
我们平时见到的多数图像都是有照射源和形成图像的场景元素对光能的反射和吸收而产生的,得到我们可见的数字图像分为一下几个步骤:
(1) 图像感知和获取
照射源入射光线照射到物体,经过反射或是折射光纤进入到人眼中,然后看到物体。而将照射能量转化为数字图像便需要用到传感器,主要的传感器有:
原理很简单: 就是通过将输入电能和对特殊类型检测能源敏感的传感器材料相结合,把输入能源转化为电压,输出的电压波再经过取样和量化便可得到离散的数字图像 f(x,y)
注:由图形形成模型来理解一下灰度级或强度级,请看下面
上面我们提到图像可由而为函数 f(x,y) 表示,其物体意义其实就来自于照射源对物体的照射,函数 f(x,y) 可由两个分量来表示:
上述两个分量分别称为入射分量和反射分量,表示为 i(x,y)、r(x, y),有:
其中:
因此图像的灰度值或强度值是由入射分量和反射分量决定的,i(x,y) 的性质取决于照射源,而r(x, y) 的性质取决于成像物体的特性,公式只是给出了 i(x,y)、r(x, y) 的一般取值范围,自然对于不同的照射源和成像物体则 i(x,y)、r(x, y) 会有不同的取值,因此数字图像灰度取值范围便是:
因此区间[Lmin,Lmax]便称为图像的灰度级,实际情况下常常令该区间为[0,L-1],其中f=0时为黑色,f=L-1时在灰度级中为白色,所有中间值是从黑色到白色之间变化的灰度色调,而图像最高和最低灰度级之间的灰度差便为对比度
(2) 图像取样和量化
为了产生一幅数字图像,我们需要把连续的感知数据转化为数字形式,便是:取样和量化。取样和量化目的便是为了将连续的感知数据离散化,而且图像的质量在很大程度上也取决于取样和量化中所用的样本数和灰度级,想了解详细过程请参考:图像的采样与量化及灰度直方图
(3) 显示数字图像
数字图像f(x,y)主要有三种表示方式:
画重点啦: 图像亮度、对比度、饱和度和锐化之间并不是彼此独立的,改变其中一个特征可能会同时引起图像其他特征的变化,至于变化的程度取决于图像本身的特性,先建立一个概念,在后面的会在详述
图像亮度通俗理解便是图像的明暗程度,数字图像 f(x,y) = i(x,y) r(x, y) ,如果灰度值在[0,255]之间,则 f 值越接近0亮度越低,f 值越接近255亮度越高。而且我们也要把亮度和对比度区分开来,正如上述提的对比度指的是最高和最低灰度级之间的灰度差。下面通过图片感受一下亮度变化对数字图像的影响:
上面白色和红色两幅图中,图的右边相对于左边增加了亮度,可以看出图像右边相对于左边亮度有了一个整体的提升,这里只是对亮度做了一个小弧度的提升,我们尝试着将亮度提升的更高,如下图:
这里需要强调的是如果我们对亮度做这么一个剧烈的改变,那么便会在改变图片强度的同时也影响了图片的饱和度、对比度和清晰度,此时两个图片右边部分饱和度、对比度和清晰度都降低了,原因是过度增加亮度导致阴影赶上了高光,因为最大灰度值是固定的,所以最低灰度值快赶上了最大灰度值,因此影响了图片的饱和度、对比度和清晰度
(1) 饱和度指的是图像颜色种类的多少, 上面提到图像的灰度级是[Lmin,Lmax],则在Lmin、Lmax 的中间值越多,便代表图像的颜色种类多,饱和度也就更高,外观上看起来图像会更鲜艳,调整饱和度可以修正过度曝光或者未充分曝光的图片。使图像看上去更加自然
(2) 对比度上面已经介绍过,指的是图像暗和亮的落差值,即图像最大灰度级和最小灰度级之间的差值,看下图:
上面白色和红色辐条图像的右侧都增加了对比度,但我们可以看出右侧的白色辐条或是红色辐条随着对比度的增加,白/红色辐条都变亮了,背景变暗了,图像看起来更加清晰。
但注意:在红色辐条中增加对比度同时也增加了饱和度,但白色辐条的饱和度没有随着亮度的增加而增加,这印证了前面说的变化的程度取决于图像本身的特性。因为饱和度对于具有鲜艳颜色,颜色丰富的图像影响很大,而对于暗淡的颜色或几乎是中性颜色影响较小
图像锐化是补偿图像的轮廓,增强图像的边缘及灰度跳变的部分,使图像变得清晰。图像锐化在实际图像处理中经常用到,因为在做图像平滑,图像滤波处理的时候经过会把丢失图像的边缘信息,通过图像锐化便能够增强突出图像的边缘、轮廓
如需了解图像锐化原理请查看博文: 图像锐化(增强)和边缘检测
从山图中我们可以看出图像白色、红色辐条的接近中心的细辐条亮度、对比度和饱和度也有了明显的提升,但外侧确没有太明显的变化,这是因为图像锐化会更多的增强边缘数据,因此影响也就更加明显
小结一下:上面三个小节分别对图像的亮度、对比度、饱和度、锐化的概念做了基本的阐述,同时配图也着重强调了图像的亮度、对比度、饱和度、锐化之间也不是完全孤立存在的,是会互相影响的,So明白了他们之间的相互影响,在以后做数字图像处理的时候能根据更好的去调节图像亮度、对比度、饱和度、锐化这些属性
不太规范的说图像分辨率可以看成是图像的大小,分辨率高图像就大,更清晰反之分辨率低图像就小。官方说法:图像分辨率指图像中存储的信息量,是每英寸图像内有多少个像素点,即:像素每英寸,单位为PPI(Pixels Per Inch),因此放大图像便会增强图像的分辨率,图像分辨率大图像更大,更加清晰,例如:一张图片分辨率是500x200,也就是说这张图片在屏幕上按1:1放大时,水平方向有500个像素点(色块),垂直方向有200个像素点(色块)
先画个重点:
对于数字图像变换,设原像素灰度为 f(i,j),转化后的像素灰度为 g(i,j),则常用的线性变换是 g(i,j)= af(i,j) + b, 其中系数 a 影响图像的对比度,系数 b 影响图像的亮度,具体如下:
(1) a=1时是原图;
(2) a>1时对比度增强,图像看起来更加清晰;
(3) a<1时对比度减弱,图像看起来变暗;
(4) b影响图像的亮度,随着增加b (b>0)和减小b (b>0),图像整体的灰度值上移或者下移, 也就是图像整体变亮或者变暗, 不会改变图像的对比度
上代码:
import cv2
import imutils
import numpy as np
def c_and_b(arg):
''''''
cnum = cv2.getTrackbarPos(trackbar_name1, wname)
bnum = cv2.getTrackbarPos(trackbar_name2, wname)
#print(bnum)
cimg = np.ones((img.shape[0], img.shape[1], 3), dtype=np.uint8)
for i in range(img.shape[0]):
for j in range(img.shape[1]):
lst = 0.1*cnum*img[i, j] + bnum
cimg[i, j] = [int(ele) if ele < 255 else 255 for ele in lst]
cv2.imshow(wname, imutils.resize(cimg, 800))
wname = 'brightness and contrast'
trackbar_name1 = 'contrast'
trackbar_name2 = 'brightness'
img = cv2.imread("E:/peking_rw/ocr_project/base_prehandle/img/li.jpg")
height, width = img.shape[:2]
img = cv2.resize(img, (int(width/height*400), 400), interpolation=cv2.INTER_CUBIC)
cv2.namedWindow(wname)
cv2.createTrackbar(trackbar_name1, wname, 10, 20, c_and_b)
cv2.createTrackbar(trackbar_name2, wname, 0, 100, c_and_b)
c_and_b(0)
if cv2.waitKey(0) == 27:
cv2.destroyAllWindows()
运行效果如下:
HSL空间:代表色相,饱和度,明度三个通道的颜色。 H: Hue 色相、 S:Saturation 饱和度、 L :Lightness 明度。例如:归一化后二维数字图像(0, 0)像素的值为(0.2,0.3,0.4),则代表H=0.2,S=0.3,L=0.4
上代码:
import cv2
import imutils
import numpy as np
def s_and_b(arg):
lsImg = np.zeros(image.shape, np.float32)
hlsCopy = np.copy(hlsImg)
l = cv2.getTrackbarPos('l', 'l and s')
s = cv2.getTrackbarPos('s', 'l and s')
#1.调整亮度饱和度(线性变换)、 2.将hlsCopy[:,:,1]和hlsCopy[:,:,2]中大于1的全部截取
hlsCopy[:, :, 1] = (1.0 + l / float(MAX_VALUE)) * hlsCopy[:, :, 1]
hlsCopy[:, :, 1][hlsCopy[:, :, 1] > 1] = 1
#HLS空间通道2是饱和度,对饱和度进行线性变换,且最大值在255以内,这一归一化了,所以应在1以内
hlsCopy[:, :, 2] = (1.0 + s / float(MAX_VALUE)) * hlsCopy[:, :, 2]
hlsCopy[:, :, 2][hlsCopy[:, :, 2] > 1] = 1
# HLS2BGR
lsImg = cv2.cvtColor(hlsCopy, cv2.COLOR_HLS2BGR)
# 显示调整后的效果
cv2.imshow("l and s", imutils.resize(lsImg, 650))
image = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/cartoon.jpg', 1)
# 图像归一化,且转换为浮点型, 颜色空间转换 BGR转为HLS
fImg = image.astype(np.float32)
fImg = fImg / 255.0
#HLS空间,三个通道分别是: Hue色相、lightness亮度、saturation饱和度
#通道0是色相、通道1是亮度、通道2是饱和度
hlsImg = cv2.cvtColor(fImg, cv2.COLOR_BGR2HLS)
l, s, MAX_VALUE = 100, 100, 100
cv2.namedWindow("l and s", cv2.WINDOW_AUTOSIZE)
cv2.createTrackbar("l", "l and s", l, MAX_VALUE, s_and_b)
cv2.createTrackbar("s", "l and s", s, MAX_VALUE, s_and_b)
s_and_b(0)
if cv2.waitKey(0) == 27:
cv2.destroyAllWindows()
运行效果如下:
图像分辨率调节就比较简单了,经常使用,opencv-python中自带了resize函数可以对图像的分辨率进行调节,resize函数官方给出定义:
cv2.resize(img, (width, height), interpolation = cv2.INTER_LINEAR)
参数一: 图像对象
参数二: (width, height)输入的图像的宽度和高度
参数三: 使用何种差值方式对图像进行缩放,由一下常用几种
import cv2
import imutils
import numpy as np
rgb_img = cv2.imread('E:/peking_rw/ocr_project/base_prehandle/img/li.jpg')
height, width = rgb_img.shape[:2]
rgb_img = cv2.resize(rgb_img, (int(width/height*100), 100), interpolation=cv2.INTER_CUBIC)
cv2.imshow('resize image', rgb_img))
if cv2.waitKey(0) == 27:
cv2.destroyAllWindows()
总结一下本文所学习的知识点: