Opencv颜色空间转换、直方图、Gamma变换

一、颜色空间转换

cv2.cvtcolor(img,code)

code——转换的标识,从什么空间转换到什么空间,常用的有:cv2.COLOR_BGR2HSV、cv2.COLOR_HSV2BGR、cv2.COLOR_GRAY2BGR、cv2.COLOR_BGR2GRAY

HSV空间:HSV空间是由美国的图形学专家A. R. Smith提出的一种颜色空间,HSV分别是色调(Hue),饱和度(Saturation)和明度(Value)。在HSV空间中进行调节就避免了直接在RGB空间中调节是还需要考虑三个通道的相关性。OpenCV中H的取值是[0, 180),其他两个通道的取值都是[0, 256),用于调节色调和明暗。

示例:

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

img = cv2.imread('scene.jpg')
# 通过cv2.cvtColor把图像从BGR转换到HSV
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# H空间中,通过增加像素灰度值可以改变图像的色调
turn_green_hsv = img_hsv.copy()
turn_green_hsv[:, :, 0] = (turn_green_hsv[:, :, 0]+150) % 180
turn_green_img = cv2.cvtColor(turn_green_hsv, cv2.COLOR_HSV2BGR)
cv2.imwrite('turn_green.jpg', turn_green_img)

# 减小饱和度会让图像损失鲜艳,变得更灰
colorless_hsv = img_hsv.copy()
colorless_hsv[:, :, 1] = 0.5 * colorless_hsv[:, :, 1]
colorless_img = cv2.cvtColor(colorless_hsv, cv2.COLOR_HSV2BGR)
cv2.imwrite('colorless.jpg', colorless_img)

# 减小明度为原来一半
darker_hsv = img_hsv.copy()
darker_hsv[:, :, 2] = 0.5 * darker_hsv[:, :, 2]
darker_img = cv2.cvtColor(darker_hsv, cv2.COLOR_HSV2BGR)
cv2.imwrite('darker.jpg', darker_img)
色调
饱和度
明暗

二、直方图

无论是HSV还是RGB,我们都较难一眼就对像素中值的分布有细致的了解,这时候就需要直方图,Opencv中直方图计算函数为:

cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate ]]) #返回hist

各参数:

channels:直方图计算的通道[0]、[1]、[2]

mask:可选的操作掩码。如果此掩码不为空,那么它必须为8位并且尺寸要和输入图像images[i]一致

histSize:表示这个直方图分成多少份(即多少个直方柱)

ranges:直方图中各个像素的值,[0,256]表示直方图能表示从0到256像素值的像素

accumulate:布尔量,表示直方图是否可以叠加

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

def calcAndDrawHist(image, color):  
    hist= cv2.calcHist([image], [0], None, [256], [0.0,255.0])  
    minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(hist)  
    histImg = np.zeros([256,256,3], np.uint8)  
    hpt = int(0.9* 256);  
      
    for h in range(256):  
        intensity = int(hist[h]*hpt/maxVal)  ###相当于归一化
        cv2.line(histImg,(h,256), (h,256-intensity), color)  
          
    return histImg

if __name__ == '__main__':  
    img = cv2.imread("scene.jpg")  
    b, g, r = cv2.split(img)     ###########按通道划分图像
  
    histImgB = calcAndDrawHist(b, [255, 0, 0])  
    histImgG = calcAndDrawHist(g, [0, 255, 0])  
    histImgR = calcAndDrawHist(r, [0, 0, 255])  
      
    cv2.imshow("histImgB", histImgB)  
    cv2.imshow("histImgG", histImgG)  
    cv2.imshow("histImgR", histImgR)  
    cv2.imshow("Img", img)  
    cv2.waitKey(0)  
    cv2.destroyAllWindows()

其中函数minMaxLoc()在C++下表示为:

void cv::minMaxLoc  (   InputArray      src,
        double *    minVal,
        double *    maxVal = 0,
        Point *     minLoc = 0,
        Point *     maxLoc = 0,
        InputArray      mask = noArray() 
    )   

参数解释

  •  src: 输入的单通道数组
  •  minVal: double类型指针,用于返回最小值的指针,如果不需要返回则设置为NULL
  •  maxVal: double类型的指针,用于返回最大值指针,如果不需要返回则设置为NULL
  • minLoc: 返回最小值位置指针(2D的情况下),如果不需要则设置为NULL
  • maxLoc: 返回最大位置指针(2D情况下),如果不需要则设置为NULL
  • mask: 可选掩模板。

表示成折线图:

import cv2  
import numpy as np  
       
img = cv2.imread('scene.jpg')  
h = np.zeros((256,256,3)) #创建用于绘制直方图的全0图像  
       
bins = np.arange(256).reshape(256,1) #直方图中各bin的顶点位置  
color = [ (255,0,0),(0,255,0),(0,0,255) ] #BGR三种颜色  
for ch, col in enumerate(color):  
    originHist = cv2.calcHist([img],[ch],None,[256],[0,256])  
    cv2.normalize(originHist, originHist,0,255*0.9,cv2.NORM_MINMAX)  
    hist=np.int32(np.around(originHist))  
    pts = np.column_stack((bins,hist))  
    cv2.polylines(h,[pts],False,col)  
       
h=np.flipud(h)  
       
cv2.imshow('colorhist',h)  
cv2.waitKey(0)  

主要用到的函数包括cv2.normalize()、np.column_stack(),enumerate()flipud()含义如下:

void cv::normalize  (   InputArray      src,
        InputOutputArray    dst,
        double      alpha = 1,
        double      beta = 0,
        int     norm_type = NORM_L2,
        int     dtype = -1,
        InputArray      mask = noArray() 
    ) 

参数解释

  • src: 输入数组
  • dst: 输出数组,与src有相同的尺寸
  • alpha: 将数组归一化范围的最大值,有默认值1
  • beta: 归一化的最小值,有默认值0
  • norm_type: 归一化方式,可以查看NormTypes()函数查看详细信息,有默认值NORM_L2
  • dtype: 当该值取负数时,输出数组与src有相同类型,否则,与src有相同的通道并且深度为CV_MAT_DEPTH(dtype)
  • mask: 可选的掩膜版 

三、Gamma变换

背景里的暗部细节是非常弱的时候,一个常用方法是考虑用Gamma变换来提升暗部细节。Gamma变换是矫正相机直接成像和人眼感受图像差别的一种常用手段,简单来说就是通过非线性变换让图像从对曝光强度的线性响应变得更接近人眼感受到的响应。具体的定义和实现,还是接着上面代码中读取的图片,执行计算直方图和Gamma变换的代码如下:

import cv2  
import numpy as np  
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

img = cv2.imread('scene.jpg') 

# 分通道计算每个通道的直方图
hist_b = cv2.calcHist([img], [0], None, [256], [0, 256])
hist_g = cv2.calcHist([img], [1], None, [256], [0, 256])
hist_r = cv2.calcHist([img], [2], None, [256], [0, 256])

# 定义Gamma矫正的函数
def gamma_trans(img, gamma):
    # 具体做法是先归一化到1,然后gamma作为指数值求出新的像素值再还原
    gamma_table = [np.power(x/255.0, gamma)*255.0 for x in range(256)]
    gamma_table = np.round(np.array(gamma_table)).astype(np.uint8)
    
    # 实现这个映射用的是OpenCV的查表函数
    return cv2.LUT(img, gamma_table)

# 执行Gamma矫正,小于1的值让暗部细节大量提升,同时亮部细节少量提升
img_corrected = gamma_trans(img, 0.5)
cv2.imwrite('gamma_corrected.jpg', img_corrected)

# 分通道计算Gamma矫正后的直方图
hist_b_corrected = cv2.calcHist([img_corrected], [0], None, [256], [0, 256])
hist_g_corrected = cv2.calcHist([img_corrected], [1], None, [256], [0, 256])
hist_r_corrected = cv2.calcHist([img_corrected], [2], None, [256], [0, 256])


fig = plt.figure()

pix_hists = [
    [hist_b, hist_g, hist_r],
    [hist_b_corrected, hist_g_corrected, hist_r_corrected]
]

pix_vals = range(256)

for sub_plt, pix_hist in zip([121, 122], pix_hists):
    ax = fig.add_subplot(sub_plt, projection='3d')
    for c, z, channel_hist in zip(['b', 'g', 'r'], [20, 10, 0], pix_hist):
        cs = [c] * 256
        #ax.bar(pix_vals, channel_hist, zs=z, zdir='y', color=cs, alpha=0.618, edgecolor='none', lw=0)
        ax.plot3D(pix_vals, channel_hist, zs=z,zdir='y',color=c)

    ax.set_xlabel('Pixel Values')
    ax.set_xlim([0, 256])
    ax.set_ylabel('Channels')
    ax.set_zlabel('Counts')

plt.show()
直方图
原图
gamma变换之后

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值