opencv学习- 对比度增强

文章目录

  • 1 灰度直方图
    • python实现
  • 2 彩色直方图
  • 3 直方图正规化
    • API
  • 4 伽码变换
  • 5 线性变换
  • 6 限制对比度的自适应直方图均衡化(CLAHE)

1 灰度直方图

  • 什么是灰度直方图
    灰度直方图是图像灰度级的函数,用来描述每个灰度级在图像矩阵中的像素个数或者占有率。
    如:
    I = ( 10 15 55 145 15 10 10 55 1 12 10 145 90 180 0 125 ) I=\begin{pmatrix}10 &15&55&145\\15&10&10&55\\1&12&10&145\\90&180&0&125\end{pmatrix} I=1015190151012180551010014555145125
    直方图的横坐标代表灰度级(0~255),纵坐标代表每一个灰度级出现的次数
    即0在 I I I中的占有率为 1 16 \frac{1}{16} 161,10在 I I I中的占有率为 4 16 \frac{4}{16} 164

python实现

  • 代码版
import numpy as np
import cv2
import matplotlib.pyplot as plt
#定义calcGrayHist函数来计算每个灰度级的出现的次数 
def calcGrayHist(image):
    # 灰度图像的高、宽
    rows, cols = image.shape
    # 存储灰度直方图
    grayHist = np.zeros([256], np.uint64) #图像的灰度级范围是0~255      
    for r in range(rows):
        for c in range(cols):
            grayHist[image[r][c]] +=1
                    
    return grayHist
 
if __name__ == "__main__":
    img = cv2.imread(r'C:\Users\h\Desktop\image\lena.jpg', cv2.IMREAD_GRAYSCALE)
    #计算灰度直方图
    grayHist = calcGrayHist(img)
    #画出直方图
    x_range = range(256)
    plt.plot(x_range, grayHist, 'r', linewidth=2, c='orange')
    #设置坐标轴的范围
    y_maxValue = np.max(grayHist)
    plt.axis([0, 255, 0, y_maxValue]) #画图范围
    plt.xlabel("gray Level")
    plt.ylabel("number of pixels")
    plt.show()

opencv学习- 对比度增强_第1张图片

  • API版
from matplotlib import pyplot as plt
import cv2
 
img = cv2.imread(r'C:\Users\h\Desktop\image\lena.jpg', cv2.IMREAD_GRAYSCALE)
plt.imshow(img, cmap=plt.cm.gray)
 
#images,必须用方括号括起来,一维数组 
#channels,是用于计算直方图的通道,这里使用灰度图计算直方图,所以就直接使用第一个通道。
#Mask,图像掩模,没有使用则填写None。
#histSize,表示这个直方图分成多少份(即多少个直方柱)。
#ranges,表示直方图中各个像素的值,[0.0, 256.0]表示直方图能表示像素值从0.0到256的像素。
#accumulate,为一个布尔值,用来表示直方图是否叠加。
 
hist = cv2.calcHist([img], [0], None, [256], [0, 256])
 
plt.figure()
plt.title("Grayscale Histogram")
plt.xlabel("gray Level")
plt.ylabel("number of pixels")
 
plt.plot(hist)
plt.xlim([0, 256])
plt.show()

2 彩色直方图

类似于灰度直方图处理

from matplotlib import pyplot as plt
import cv2
 
img = cv2.imread(r'C:\Users\h\Desktop\image\lena.jpg', cv2.IMREAD_ANYCOLOR)
 
chans = cv2.split(img)
colors = ('b', 'g', 'r')
 
plt.figure()
plt.title("Color Histogram")
plt.xlabel("gray Level")
plt.ylabel("number of pixels")
 
for (chan, color) in zip(chans, colors):
    hist = cv2.calcHist([chan], [0], None, [256], [0, 256])
    plt.plot(hist, color = color)  # 赋予各自颜色 
    plt.xlim([0, 256])  # 设置当前x轴 
plt.show()

opencv学习- 对比度增强_第2张图片


3 直方图正规化

假设输入图像为 I I I,将最小灰度级记为 I m i n I_{min} Imin,最大灰度级记为 I m a x I_{max} Imax
输出图像为 O O O,灰度级范围为 [ O m i n , O m a x ] [O_{min},O_{max}] [Omin,Omax],则
O = I − I m i n I m a x − I m i n ( O m a x − O m i n ) + O m i n O=\frac{I-I_{min}}{I_{max}-I_{min}}(O_{max}-O_{min})+O_{min} O=ImaxIminIImin(OmaxOmin)+Omin
一般令 O m a x = 255 O_{max}=255 Omax=255, O m i n = 0 O_{min}=0 Omin=0.


API

cv2.normalize(src, dst, alpha, beta, norm_type, dtype, mask)

详细:

src-输入数组
dst-输出数组,支持原地运算
alpha-range normalization模式的最小值
beta-range normalization模式的最大值,不用于norm normalization(范数归一化)模式。
normType-归一化的类型,可以有以下的取值:
1. NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用
2. NORM_INF: 此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化数组的C-范数(绝对值的最大值)
3.NORM_L1 : 归一化数组的L1-范数(绝对值的和)
4.NORM_L2: 归一化数组的(欧几里德)L2-范数
dtype-dtype为负数时,输出数组的type与输入数组的type相同;否则,输出数组与输入数组只是通道数相同,而tpye=CV_MAT_DEPTH(dtype).
mask-操作掩膜,用于指示函数是否仅仅对指定的元素进行操作。

适用于:灰度级主要在0 ~ 150之间,造成图像对比度较低,可用直方图归一化将图像灰度级拉伸到0~255,使其更清晰。

#直方图正规化API
#灰度级主要在0~150之间,造成图像对比度较低,可用直方图正规化将图像灰度级拉伸到0~255,使其更清晰
import cv2
import numpy as np
import matplotlib.pyplot as plt
 
#灰度图像转化为ndarray类型
if __name__ == "__main__":
    src = cv2.imread(r'C:\Users\h\Desktop\image\low.jpg', cv2.IMREAD_ANYCOLOR)
    # dst = np.zeros_like(src)
    cv2.normalize(src, dst,0, 255, cv2.NORM_MINMAX, cv2.CV_8U) #公式
    cv2.imshow("src", src)
    cv2.imshow("dst", dst)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    #计算灰度直方图
    grayHist = cv2.calcHist([src], [0], None, [256], [0, 256])
    grayHist1 = cv2.calcHist([dst], [0], None, [256], [0, 256])
    #画出直方图
    x_range = range(256)
    plt.plot(x_range, grayHist, 'r', linewidth=1.5, c='black')
    plt.plot(x_range, grayHist1, 'r', linewidth=1.5, c='b')
    #设置坐标轴的范围
    y_maxValue = np.max(grayHist)
    plt.axis([0, 255, 0, y_maxValue]) #画图范围
    plt.xlabel("gray Level")
    plt.ylabel("number of pixels")
    plt.show()

normalize可以处理多通道矩阵,即彩色图片可以增强

4 伽码变换

伽马变换(非线性变换)实际上就是对矩阵的每个值进行幂运算
O ( r , c ) = I ( r , c ) γ , 0 ≤ r < H , 0 ≤ c < W O(r,c)=I(r,c)^\gamma ,0\leq r<H,0\leq c<W O(r,c)=I(r,c)γ,0r<H,0c<W
适用于:灰度值主要集中在灰度直方图两侧,即灰度值较低和较高的范围内,可用伽马变换修正

import cv2
import numpy as np
 
#灰度图像转化为ndarray类型
I = cv2.imread(r'C:\Users\h\Desktop\image\lena.jpg', cv2.IMREAD_ANYCOLOR)
#图像归一化
fI = I/255.0
#伽马变化
gamma = 0.4
O = np.power(fI, gamma)
 
#显示伽马变化后的结果
cv2.namedWindow("I", cv2.WINDOW_NORMAL)
cv2.namedWindow("O", cv2.WINDOW_NORMAL)
cv2.imshow("I", I)
cv2.imshow("O", O)
cv2.waitKey(0)
cv2.destroyAllWindows()

5 线性变换

假设输入图像为 I I I,宽为 W W W,高为 H H H,输出图像为 O O O,图像的线性变换为:
O ( r , c ) = a ∗ I ( r , c ) + b , 0 ≤ r < H , 0 ≤ c < W O(r,c)=a*I(r,c)+b, 0\leq r<H, 0\leq c<W O(r,c)=aI(r,c)+b,0r<H,0c<W
拉伸图像,提升对比度
压缩图像,降低对比度

import cv2
import numpy as np
    
img = cv2.imread(r'C:\Users\x\Desktop\OpenCV-Pic\4\img4.jpg', cv2.IMREAD_GRAYSCALE)#GRAYSCALE
 
#线性变换
a = 2
O = float(a) * img
O[O>255] = 255 #大于255要截断为255
    
#数据类型的转换
O = np.round(O)
O = O.astype(np.uint8)
    
#显示原图与变换后的图的效果
cv2.imshow("img", img)
cv2.imshow("O", O)
cv2.waitKey(0)
cv2.destroyAllWindows()

6 限制对比度的自适应直方图均衡化(CLAHE)

在出现过于高的对比度时(超出预设好的"限制对比度",超出的部分会被裁剪,然后均匀分配到其他区域,这样就重构了直方图。

#限制对比度的自适应直方图均衡化
import cv2
 
src = cv2.imread(r'C:\Users\h\Desktop\image\lena.jpg', cv2.IMREAD_GRAYSCALE)

#创建CLAHE对象 clipLimit限制对比度,tileGridSize块的大小
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
#限制对比度的自适应阈值
dst = clahe.apply(src)
    
cv2.imshow("src", src)
cv2.imshow("clahe",dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

opencv学习- 对比度增强_第3张图片

节选:
原文:https://blog.csdn.net/qq_40755643/article/details/84032773


对比度的拉伸受图像噪声的影响会很明显,在去除噪声后再使用对比度增强效果会更好

你可能感兴趣的:(计算机视觉)