CV:图像色彩空间及色彩处理

基本概念

RGB空间

RGB 是最基本、最常用、最接近硬件的色彩空间表示。

在这里插入图片描述

但是真实世界中还有光照、遮挡、阴影等多种情况,而且人眼对RGB三种颜色分量的敏感度也是不一样的,如果色彩的相似性直接用欧式距离来度量,结果会与视觉直观有很大差距。
所以,RGB适合与显示系统,但是不适合图像处理。

openCV提取不同通道的颜色

import cv2 as cv
src=cv.imread('rgb.jpg')
cv.namedWindow('first_image', cv.WINDOW_AUTOSIZE)
cv.imshow('first_image', src)

#三通道分离形成单通道图片
b, g, r =cv.split(src)
cv.imshow("second_blue", b)
cv.imshow("second_green", g)
cv.imshow("second_red", r)

在这里插入图片描述

HSV空间

  • H:Hue,色调,色相
  • S:Saturation,饱和度,色彩纯净度
  • V:value,明度

HSV更接近人眼的直观感受。具体来说:

H参数表示色彩信息,即所处的光谱颜色的位置。该参数用角度量来表示,红、绿、蓝分别相隔120度。互补色分别相差180度。

纯度S为一比例值,范围从0到1,它表示成所选颜色的纯度和该颜色最大的纯度之间的比率。S=0时,只有灰度。

V表示色彩的明亮程度,范围从0到1。有一点要注意:它和光强度之间并没有直接的联系。

怎么理解HSV呢?

这里引入极坐标系,红蓝绿三个颜色分别位于0度,120度和240度,在色彩极坐标系中,“纯度”与当前色彩的角度位置有关,越接近红-绿-蓝对应的角度,因此,纯度也称为色相,顾名思义,就是用当前色彩与三原色之间的相位关系来描述。

在极坐标系中,矢量除了相位以外,还有“模”的关系,原点是“灰色”,模值越大,色彩就越鲜艳,最大值是255。这里的“模”值就是饱和度。
在这里插入图片描述
但是如何形容颜色的亮度呢?我们引入三维直角坐标系,三个坐标轴分别表示RGB的取值。很显然,原点(0,0,0)是黑色,(255,255,255 )是白色,(255,0,0)红色,(0,255,0)绿色,(0,0,255)蓝色。
如果从原点出发,到(255,255,255)白色连一条对角线,这条对角线就是“明度”轴了。越接近原点就越“暗”, 越接近白色的对角点就越“亮”。

在这里插入图片描述
如果回到之前的极坐标系,亮度应该如何表示呢?显然,我们需要引入一个纵轴表示明暗关系。
在这里插入图片描述
但是上面的图并不是特别“科学”,因为最“暗”的原点处,应该是一个点,整个色彩空间应该是一个圆锥的形状。
在这里插入图片描述

  • openCV 中HSV色彩空间的转换

跑一下openCV 帮助文档中的经典例子,随手拿起手边的蓝色电脑内胆包被成功捕获了。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Sep 15 15:05:19 2019
"""

import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while(1):
    # Take each frame
    _, frame = cap.read()
    # Convert BGR to HSV
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    # define range of blue color in HSV
    lower_blue = np.array([100,50,50])
    upper_blue = np.array([140,255,255])
    # Threshold the HSV image to get only blue colors
    mask = cv2.inRange(hsv, lower_blue, upper_blue)
    # Bitwise-AND mask and original image
    res = cv2.bitwise_and(frame,frame, mask= mask)
    cv2.imshow('frame',frame)
    cv2.imshow('mask',mask)
    cv2.imshow('res',res)
    k = cv2.waitKey(5) & 0xFF
    if k == 27:
        break
cv2.destroyAllWindows()

在这里插入图片描述
注意其中这一句:

hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

这一句是将摄像头捕获的色彩从RGB空间转换到HSV空间,随后的代码用HSV方式指定特定的色彩范围。第一个值是H,就是色相,在openCV的HSV定义中,蓝色是在120度,这里指定100-140之间,S和V的取值在50-255之间。
更多色彩转换,见帮助文档: https://docs.opencv.org/3.1.0/de/d25/imgproc_color_conversions.html

HSL空间

HSL与HSV的定义很类似,H也是色相,S也是饱和度,L则代表brightness,是亮度。亮度越高,越接近白色,越低,越接近黑色。而HSV中的最后一个值明度,越小越接近黑色,越大,色彩越鲜明。可见,HSL的定义更符合人眼的视觉感受。
H:
在这里插入图片描述
S:
在这里插入图片描述
L:
在这里插入图片描述

色彩变换

灰度变换

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

im0 = Image.open('car.jpg')

im_grey = im0.convert('L') # 灰度变换
im_grey.show()

在这里插入图片描述

色彩反向、调整像素区间

im = np.array(im_grey)
im2 = 255-im # 对图像进行反向处理
im3 = (100/255)*im+100 #将图像的像素变换到100-200之间
im4 = 255*(im/255)**2 # 对图像像素值平方后得到的图像

plt.subplots()
plt.subplot(131), plt.imshow(im2)
plt.subplot(132), plt.imshow(im3)
plt.subplot(133), plt.imshow(im4)

在这里插入图片描述

增强对比度

对比度指的是一幅图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,差异范围越大代表对比度越大,差异范围越小代表对比度越小。

对比度增强技术主要解决图像灰度级范围较小造成的对比度低问题,目的是将图像的灰度级放大到指定的程度,使图像中的细节看起来更加清晰。

在这里插入图片描述

直方图均衡化

直方图均衡化是将一副图像的灰度直方图变平,使得变换后图像中的每个灰度值的分布概率相同。该方法通常用于是灰度值进行归一化,可以增强图像的对比度。

# 直方图均衡化
import numpy as np

def histeq(im, nbr_bins=256):
    # 计算图像的直方图
    imhist, bins = np.histogram(im.flatten(), nbr_bins, normed=True)
    cdf = imhist.cumsum() # 累计分布函数
    cdf = 255*cdf/cdf[-1] # 归一化
    im2 = np.interp(im.flatten(), bins[:-1], cdf)
    
    return im2.reshape(im.shape), cdf


from PIL import Image
import matplotlib.pyplot as plt

im0 = Image.open('car.jpg')

im_grey = np.array(im0.convert('L')) # 灰度变换, 并转化为numpy array

im2,cdf = histeq(im_grey)

plt.subplots()
plt.subplot(121), plt.imshow(im_grey)
plt.subplot(122), plt.imshow(im2)

在这里插入图片描述

图像平滑/减少噪声

图像平均

图像平均是一种减少图像噪声的简单方式,通常用于艺术特效。简单滴说就是将所有图像求和做平均。

高斯滤波

将图像与高斯核做卷积得到
I σ = I G σ I_\sigma = I * G_\sigma
其中I代表一个图像,G表示标准差为 δ \delta 的二维高斯核
G σ = 1 2 π σ 2 e ( x 2 + y 2 ) / 2 σ 2 G_\sigma = \frac{1}{2\pi\sigma^2}e^{-(x^2+y^2)/2\sigma^2}

from PIL import Image
from numpy import *
from scipy.ndimage import filters

# 对灰度图模糊
im = array(Image.open('car.jpg').convert('L'))
im2 = filters.gaussian_filters(im,5)

# 对彩色图模糊, 要求每个通道进行操作
im = array(Image.open('car.jpg'))
im2 = zeros(im.shape)
for i in range(3):
	im2[:,:,i] = filters.gaussian_filter(im[:,:,i],5)
im2 = unit8(im2)

openCV也提供了很多滤波工具,例如:

blur: 对各种噪声都有一定的抑制作用
GaussianBlur: 对随机噪声比较好,对椒盐噪声效果不好
medianBlur: 对椒盐噪声效果比较好
fastNlMeansDenoising: 非局部去噪,速度很慢,可以调参的去噪方法, 只支持输入是灰度图像的
fastNlMeansDenoisingColored: 同上,去噪针对彩色图像

椒盐噪声就是非常零散的,近似呈均匀分布的散点状白色/黑色噪声,如下图。对椒盐噪声中值滤波效果比较好,对高斯噪声非局部均值去噪效果比较好.
在这里插入图片描述

图像梯度

图像的梯度向量包括两层含义,一个是梯度的大小, 描述了图像强度变化的大小,另一个是梯度的方向,描述了图像强度变化的方向。

sobel算子/scharr算子

Sobel 算子是高斯平滑与微分操作的结合体,所以它的抗噪声能力很好,可以设定求导的方向(xorder 或 yorder),还可以设定使用的卷积核的大小(ksize),如果 ksize=-1,会使用 3x3 的 Scharr 滤波器,它的的效果要比 3x3 的 Sobel 滤波器好(而且速度相同,所以在使用 3x3 滤波器时应该尽量使用 Scharr 滤波器)。 3x3 的 Scharr 滤波器卷积核如下

在这里插入图片描述

prewitt算子

Prewitt算子是一种一阶微分算子的边缘检测,利用像素点上下、左右邻点的灰度差,在边缘处达到极值检测边缘,去掉部分伪边缘,对噪声具有平滑作用 。其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成的,这两个方向模板一个检测水平边缘,一个检测垂直边缘。
在这里插入图片描述

Laplacian 算子

拉普拉斯算子可以使用二阶导数的形式定义,可假设其离散实现类似于二阶 Sobel 导数,事实上, OpenCV 在计算拉普拉斯算子时直接调用 Sobel 算子。
  在这里插入图片描述

scipy和opencv都提供了相应工具,例如:

from PIL import Image
from numpy import *
from scipy.ndimage import filters

im = array(Image.open('car.jpg').convert('L'))

# sobel filter
imx = zeros(im.shape)
filters.sobel(im,1,imx)

imy = zeros(im.shape)
filters.sobel(im, 0, imy)

matnitude = sqrt(imx**2+imy**2)

import matplotlib.pyplot as plt

plt.subplots()
plt.subplot(121), plt.imshow(imx)
plt.subplot(122), plt.imshow(imy)

在这里插入图片描述
prewitt滤波器, 也可以调用scipy.ndimage的filters模块得到。

opencv中,直接调用Sobel函数或者Laplacian函数就可以, 例如:


import cv2
from matplotlib import pyplot as plt 

img = cv2.imread('me.jpg',0)

laplacian = cv2.Laplacian(img, cv2.CV_64F)
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0,ksize=5)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1,ksize=5)


plt.subplot(2,2,1),plt.imshow(img,cmap='gray')
plt.title('Original'),plt.xticks([]),plt.yticks([])
plt.subplot(2,2,2),plt.imshow(laplacian,cmap='gray')
plt.title('Laplacian'),plt.xticks([]),plt.yticks([])
plt.subplot(2,2,3),plt.imshow(sobelx,cmap='gray')
plt.title('Sobel_X'),plt.xticks([]),plt.yticks([])
plt.subplot(2,2,4),plt.imshow(sobely,cmap='gray')
plt.title('Sobel_Y'),plt.xticks([]),plt.yticks([])
plt.show()


在这里插入图片描述

参考及更多阅读

OpenCV图像噪声与去噪函数方法对比使用介绍:
https://cloud.tencent.com/developer/article/1165771
opencv图像梯度:
https://blog.csdn.net/u010682375/article/details/70140803
opencv 彩色图像对比度增强:

发布了111 篇原创文章 · 获赞 118 · 访问量 28万+

猜你喜欢

转载自blog.csdn.net/happyhorizion/article/details/100752747