计算机视觉4:灰度变换和直方图修正

1. 点运算

1.1 点运算的基本概念

图像点运算是指对图像中的每一个像素点进行计算,使其输出的每一个像素值仅由对应点的值来决定,可以理解为点到点之间的映射。

通过点运算,输出图像每个像素的灰度值仅仅取决于输入图像中相对应像素的灰度值。

1.2 点运算的目标与分类

点运算时实现图像增强处理的常用方法之一,经常用于改变图像的灰度范围以及分布。通过这种方法可以使图像的动态范围增大,增强图像的对比度,使图像变得更加清晰。

点运算分为灰度变换和直方图修改两大方法。

1.3 点运算的特点和应用

从算法原理上看,点处理指的是仅根据图像中像素的原灰度值按一定的规则来确定新的灰度值。

特点:光度学标定、显示标定、对比度增强、轮廓线、裁剪。

2. 灰度变换

2.1 灰度变换的基本概念

改善图像的质量可以采用灰度变换法,通过扩展输入图像的动态范围达到图像增强的目的。

灰度变化可使图像动态范围加大,图像对比度增强、图像清晰、特征明显,是图像增强的重要手段。

灰度变换主要利用点运算来修正像素灰度,由输入像素点的灰度值确定相应输出点的灰度值,是一种基于图像变换的操作。

2.2 灰度变换的作用

  • 改善图像的质量,使图像能够显示更多的细节,提高图像的对比度(对比度拉伸)。
  • 有选择地突出图像感兴趣的特征,或者抑制图像中不需要的特征。
  • 可以有效地改变图像的直方图分布,使像素的分布更为均匀。

2.3 灰度变换的方法

根据函数性质,灰度变换方法分为:线性灰度变换、分段线性灰度变换、非线性灰度变换(包括对数函数变换和幂律函数变换(伽马变换))。

2.4 灰度化

如果每个像素的R、G、B完全相同,也就是R=G=B=D,那么该图像就是灰度图像,其中D被称为各个像素的灰度值。

2.4.1 加权平均值法

加权平均值法可以分为浮点数实现方式和整数实现方式。

当采用0.299份的红色、0.587份的绿色、0.114份的蓝色混合后可以得到白色,因此彩色图像可以根据一下公式变为灰度图像:

D = 0.299 * R+0.587*G+0.114*B

其中,D表示点(x,y)转换后的灰度值,R、G、B为点(x,y)的3个单色分量。这个公式一般称为经验公式。还可以用整数实现的方式,公式如下:

D = (R * 30 + G * 59 + B * 11)÷ 100

2.4.2 取最大值法

取最大值法使将彩色图像中3个分量的最大亮度最大值作为灰度图像的灰度值。

D = max(R,G,B)

灰度处理首先读入图像的复制文件到内存中,然后找的R、G、B中的最大值,使颜色的分量值都相等且等于最大值,这样就可以使图像变成灰度图像。

2.4.3 平均值法

平均值法将彩色图像中3个分量的亮度值求平均值,从而得到一个灰度值,将其作为灰度图像的灰度。

D = (R + G + B) ÷ 3

代码实例:

# 加权平均值法实现图像灰度化
import cv2  as cv  
import numpy as np

image = cv.imread("test.jpg")
h = np.shape(image)[0]
w = np.shape(image)[1]
print(h)
print(w)
grayimg = np.zeros((h,w,3),np.uint8)
 
for i in range(h):  
    for j in range(w):
        # image 是原始的彩色图像,它是一个三维数组,其中每个元素包含三个颜色通道的值:红色、绿色和蓝色。
        # image[i,j][0]、image[i,j][1] 和 image[i,j][2] 分别是图像中第 i 行第 j 列的红色、绿色和蓝色通道的值。
        grayimg[i,j] = 0.3 * image[i,j][0] + 0.59 * image[i,j][1] +  0.11 * image[i,j][2]

cv.imshow("srcImage", image)
cv.imshow("grayImage", grayimg)
 
cv.waitKey(0)  



# 最大值法是实现图像灰度化
import cv2  as cv  
import numpy as np

image = cv.imread("test.jpg")
h = np.shape(image)[0]
w = np.shape(image)[1]
grayimg = np.zeros((h,w,3),np.uint8)

for i in range(h):  
    for j in range(w):  
        grayimg[i,j] = max(image[i,j][0], image[i,j][1], image[i,j][2])  

cv.imshow("srcImage", image)
cv.imshow("grayImage", grayimg)
 
cv.waitKey(0)  
cv.destroyAllWindows()


# 平均值法实现图像灰度化
import cv2  as cv  
import numpy as np

image = cv.imread("test.jpg")
h = np.shape(image)[0]
w = np.shape(image)[1]
grayimg = np.zeros((h,w,3),np.uint8)

for i in range(h):
    for j in range(w):  
        grayimg[i,j] = (image[i,j][0] + image[i,j][1] + image[i,j][2])/3  

cv.imshow("srcImage", image)
cv.imshow("grayImage", grayimg)
 
cv.waitKey(0)  
cv.destroyAllWindows()

 

 

2.5 对比度

对比度(contrast)是指画面的明亮部分和阴暗部分的灰度比值。一幅图像对比度越高,图像中被照物体的轮廓越分明可见,图像越清晰,色彩也越鲜明艳丽;对比度小,则会让整个画面都灰蒙蒙的。

2.6 灰度的线性变换

如果检查表明规定的灰度分级没有得到充分利用,就可以用线性灰度变换来解决。

灰度的线性变换是指将图像中所有点的灰度按照线性灰度变换函数进行变换。

直线方程有好多种,比如点斜式、斜截式、截距式、两点式、一般式,其中,点斜式的形式如下:

y - y1 = k (x - x1)

2.7 分段线性变换

分段线性灰度变换将原图像灰度范围划分为两段或更多段,对感兴趣的目标或灰度区间进行增强,对其他不感兴趣的灰度区间进行抑制。该方法在红外图像的增强中应用较多。

分段线性变换增强效果的好坏关键在于分段点的选取及各段增强参数的选取。选取的方法包括手工选取和计算机自适应选取。

2.8 对数变化和反对数变换

对数变换和反对数变换属于非线性变换。对数变换的公式为:

 s = c * log (1 + r )

其中,c为常数,r>=0.。

对数变换有两个作用:

  1. 对数曲线在像素值较低的区域的斜率较大,在像素值较高的区域斜率较低。所以图像经过对数变换之后在较暗的区域对比度将得到提升,因而能增强图像暗部的细节。
  2. 需要使用对数变换,使得傅里叶频谱的动态范围被合理的非线性压缩。

在opencv中,图像对数变换的实现可以直接通过对图像中每个元素运算上述公式完成,也可以通过矩阵整体操作来完成。

2.9 幂律变换

        幂律变换也称伽马(Gamma)变换或指数变换,是一种常用的灰度非线性变换。幂律变换的公式如下;

s = c * x ^{\gamma }

        公式中,x为灰度图像的输入值。取值范围为0~1,s为经过伽马变化后的灰度输出值。c为灰度缩放系数,通常取1。\gamma为伽马因子大小,用于控制整个变换的缩放程度。\gamma值以1为界限,\gamma值越小,对图像低灰度部分的扩展作用就越强;\gamma值越大,对图像高灰度部分的扩展作用就越强。

        当\gamma小于1时,低灰度区间拉伸,高灰度区间压缩;当\gamma大于1时,低灰度区间压缩,高灰度区间拉伸;当\gamma等于1时,简化成恒等变换。

        伽马变换多用于图像整体偏暗、扩展灰度级,还可用于图像有“冲淡”的外观(很亮白),需要压缩中高以下的大部分灰度级的情况下。伽马变换就是用来图像增强的,提升了暗部细节,简单来说就是通过非线性变换让图像从曝光强度的线性响应变得更接近人眼感受的响应,即将漂白(相机曝光)或过暗(曝光不足)的图片进行矫正。

3. 直方图修正

直方图修正包括直方图均衡化和直方图规定化。

3.1 直方图的概念

图像的灰度直方图描述了图像中灰度的分布情况,能够很直观的展示出图像中各个灰度级所占的多少。

图像的灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素个数。简单的说,就是把一幅图像中每一个像素出现的次数都先统计出来,然后把每一个像素出现的次数除以总的像素个数,得到的就是这个像素出现的频率。然后把像素与该像素出现的频率用图表示出来,就是灰度直方图。从图形上来说,灰度直方图是一个二维图,横坐标为像素中各个像素的灰度值,纵坐标表示具有各个灰度值的像素在图像中出现的次数。

在OpenCV中封装了直方图的计算函数calcHist,该函数能够同时计算多个图像、多个通道、不同灰度范围的灰度直方图。具体函数声明如下:

calcHist (images, channels, mask, histSize, ranges[, hist[, accumulate]] )  →  hist

  • images:表示图像矩阵数组,这些图像必须有相同大小和相同的深度;
  • channels:表示要计算直方图的通道个数;
  • mask:表示可选的掩码,不使用时可设为空;
  • histSize:表示直方图每个维度的大小;
  • hist:表示输出的直方图;
  • ranges:表示直方图每个维度要统计的灰度级的范围;
  • accumulate:表示累计标志,默认值为Flase。

代码实例1:某图像灰度直方图

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('test.jpg',0)
# img.ravel()将图像数组展平成一维数组,256是直方图的bin数量,[0,256]是直方图的值范围,表示像素值从0到255。
plt.hist(img.ravel(),256,[0,256]);
plt.show()

一般使用Matplotlib绘制直方图。matplotlib.pyplot.hist()函数可以直接统计绘制直方图,统计函数为calcHist()或np.histogram()。

代码实例2:绘制BGR直方图

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('test.jpg',1)   # 参数1表示以彩色模式读取图像。
color = ('b','g','r')
# 使用enumerate函数遍历颜色通道标识符,并为每个通道分配一个索引i。
for i,col in enumerate(color):
    # 使用OpenCV的calcHist函数计算当前颜色通道的直方图。
    # [img]是图像数组列表,[i]是当前通道的索引,None是直方图的掩码(这里未使用),
    # [256]是直方图的bin数量,[0,256]是直方图的值范围。
    histr = cv2.calcHist([img],[i],None,[256],[0,256])
    plt.plot(histr,color = col)
    plt.xlim([0,256])    # 设置x轴的范围为0到256,以匹配直方图的值范围。
plt.show()

代码实例3:原始计算灰度直方图的方法

import sys
import numpy as np
import cv2
import matplotlib.pyplot as plt

def main():
    img=cv2.imread('test.jpg',0)   # 以灰度模式(0)读取。
    #得到计算灰度直方图的值
    xy=xygray(img)   

    #画出灰度直方图
    x_range=range(256)   # 创建一个范围从0到255的x轴数据。
    # 绘制直方图,其中"r"表示绘制红色线条,linewidth=2设置线条宽度为2,c='black'设置线条颜色为黑色。
    plt.plot(x_range,xy,"r",linewidth=2,c='black')
    #设置坐标轴的范围
    y_maxValue=np.max(xy)   # 计算直方图的最大值。
    plt.axis([0,255,0,y_maxValue])    # 设置x轴和y轴的范围。
    #设置坐标轴的标签
    plt.xlabel('gray Level')
    plt.ylabel("number of pixels")
    plt.show()

def xygray(img):
    #得到高和宽
    rows,cols=img.shape
    #存储灰度直方图  创建一个大小为256的数组xy,用于存储灰度直方图,初始值为0。
    xy=np.zeros([256],np.uint64)
    # 通过两层嵌套循环遍历图像的每个像素,并在xy数组中对应的灰度值位置加1。
    # 返回xy数组,即灰度直方图。
    for r in range(rows):
        for c in range(cols):
            xy[img[r][c]] += 1
    #返回一维ndarry
    return xy

main()

3.1 直方图均衡化

直方图均衡化是一种常见的增强图像对比度的方法,直方图均衡化就是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。

直方图均衡化中使用的是累积分布函数。

使用直方图均衡化来改善图像质量,通常有两种方法:一种是不通过OpenCV函数:另外一种是通过OpenCV函数equalizeHist(这种方式不懂原理也可以使用,只要把原图像输入即可得到均衡化的图像输出)。equalizeHist函数对图像进行直方图均衡化,声明如下:

equalizeHist (src[, dst] )  →  dst

  • src:表示输入图像,即源图像,但需要为8位单通道的图像;
  • dst:表示输出结果,需要和源图像有一样的尺寸和类型。

代码实例1:灰度图像直方图均衡化

import cv2
import numpy as np

img = cv2.imread("test.jpg", 1)
# 使用cvtColor函数将彩色图像转换为灰度图像。
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("src", gray)
# 使用equalizeHist函数对灰度图像进行直方图均衡化。
dst = cv2.equalizeHist(gray)
cv2.imshow("dst", dst)

cv2.waitKey(0)
cv2.destroyAllWindows()

代码实例2:实现彩色图像的直方图均衡化

先用split()方法将彩色图像的三个通道拆分,然后分别进行均衡化,最后使用merge()方法将均衡化后的三个通道进行合并。

import cv2
import numpy as np

img = cv2.imread("test.jpg", 1)
cv2.imshow("src", img)

# 彩色图像均衡化,需要分解通道 对每一个通道均衡化
# 使用split函数将彩色图像分解为三个独立的通道:蓝色(b)、绿色(g)和红色(r)。
(b, g, r) = cv2.split(img)
bH = cv2.equalizeHist(b)  # 对蓝色通道进行直方图均衡化处理。
gH = cv2.equalizeHist(g)  # 对绿色通道进行直方图均衡化处理。
rH = cv2.equalizeHist(r)  # 对红色通道进行直方图均衡化处理。
# 使用merge函数将均衡化后的三个通道重新合并为一个彩色图像。
result = cv2.merge((bH, gH, rH))
cv2.imshow("dst", result)

cv2.waitKey(0)
cv2.destroyAllWindows()

代码实例3:YUV直方图均衡化

import cv2
import numpy as np
img = cv2.imread("test.jpg", 1)
# 使用cvtColor函数将图像从BGR颜色空间转换到YCrCb颜色空间。
imgYUV = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
cv2.imshow("src", img)

# 使用split函数将YCrCb图像分解为三个独立的通道:Y(亮度)、Cr(红色色度)、Cb(蓝色色度)。
channelsYUV = cv2.split(imgYUV)

# 对Y通道(亮度通道)进行直方图均衡化处理。
channelsYUV[0] = cv2.equalizeHist(channelsYUV[0])

# 使用merge函数将经过直方图均衡化的Y通道与未改变的Cr和Cb通道重新合并。
channels = cv2.merge(channelsYUV)

# 将合并后的YCrCb图像转换回BGR颜色空间,以便显示。
result = cv2.cvtColor(channels, cv2.COLOR_YCrCb2BGR)

cv2.imshow("dst", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

参考学习书总结:OpenCv4.5 计算机视觉开发实战(基于python)

供自己学习复习使用,继续学习ing...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

听说你还在搞什么原创~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值