目录
(一)彩色模型介绍
计算机中的颜色表示
在计算机中,显示器的任何颜色〈色彩全域〉都可以自红、绿、蓝3种颜色组成,称为三基色.每种基色的取值范围是0~255.任何颜色都可以用这3种颜色按不同的比例混合而成, 这就是三原色原理. 在计算机中, 三原色的原理可以这样解释:
- 计算机中的任何颜色都可以由3种颜色按不同比例混合而成;而每种颜色也都可以分解成三种基本颜色;
- 三原色之间相互独立,任何一种颜色都不能由其余两种颜色组成;
- 混合色的饱和度由3种颜色的比例来决定 混合色的亮度为3种颜色的亮度之和;
彩色模型也称彩色空间或彩色系统, 是用来精确标定和生成各种颜色的一套规则和定义, 它的用途是在某些标准下用通常可接受的方式简化彩色规范. 彩色模型通常可以采用坐标系统来描述, 而位于系统中的每种颜色都由坐标空间中的单个点来表示。
如今使用的大部分彩色模型都是面向应用或是面向硬件, 比如众所周知的针对彩色电视器的RGB( 红、绿、蓝〉模型, 以及面向彩色打印机的CMY(青、深红、黄〉和CMYK(青、深红、黄、黑〉模型。而HSI(色调、饱和度、亮度〉模型非常符合人眼描述和解释颜色的方式。此外, 目前广泛使用的彩色模型还有如:HSV模型、YUV 模型、YIQ模型、Lab模型等。下面将分别介绍这些彩色模型并给出它们与最为常用的RGB模型之间的转换方式。
1.1 RGB模型
RGB模型是工业界的一种颜色标准. 是通过对红(Red)、绿(Green)、蓝(Blue)3种颜色亮度的变化以及它们相互之间的叠加来得到各种各样的颜色的。该标准儿乎包括了人类视觉所能感知的所有颜色,是目前运用最广的颜色模型之一。
RGB彩色空间对应的坐标系统是如图所示的立方体. 红、绿和蓝位手立方体的3个顶点上:青、深红和黄位于另外3个顶点上:黑色在原点处, 而白色位于距离原点最远的顶点处, 灰度等级就沿这两点连线分布: 不同的颜色处于立方体外部和内部, 因此可以用一个3维向量来表示。例如,在所有颜色均己归一化到(O, 1)的情况下,蓝色可表示为(O, 0, 1),而灰色可由向量(0.5, 0.5, 0.5)来表示。
红、绿、蓝在3个角上,青、深红、黄在另外3个角上,黑色在原点处,白色位于离原点最远的角上;灰度等级沿着主对角线从黑色到白色分布。为了方便,上述将R、G、B值归一化至[0,1]区间。在RGB彩色模型中,任何一幅图像都由3个图像分量组成,每个分量图像都是其原色图像。对于RGB图像,每一副红、绿、蓝图像都是8比特图像,3幅图像送至显示器时在屏幕上混合成一幅彩色图像。
1.2 CMY、CMYK模型
CMY模型(Cyan、Magenta、Yellow):
是采用青、品红、黄色3种基本原色按一定比例合成颜色的方法。由于色彩的显示不是直接来自于光线的色彩,而是由光线被物体吸收掉一部分之后反射回来的剩余光线产生,因此CMY模型又称为减色法混色模型。当光线都被吸收时成为黑色,都被反射时成为白色。
图像是人类获取和交换信息的主要来源,因此,图像处理的应用领域必然涉及到人类生活和工作的方方面面。随着人类活动范围的不断扩大,图像处理的应用领域也将随之不断扩大。像CMY 模型这样的减色混合模型正好适用于彩色打印机和复印机这类需要在纸上沉积彩色颜料的设备, 因为颜料不是像显示器那样发出颜色, 而是反射颜色。例如,当青色颜料涂覆的表面用。白光照射时, 从该表面反射的不是红光, 而是从反射的白光中减去红色得到的青色(白光本身是等量的红、绿、蓝光的组合). CMY模型的颜料混合效果如图7.6所示, 注意这里的混合是原色的相减, 与RGB模型的混合正好相反。RGB与CMY模型之间的转换:
CMYK模型 :
等量的颜料原色(青、品红和黄)可以混合产生黑色。然而在实际运用中, 通过这些颜色混合产生的黑色是不纯的。因此, 为产生真正的黑色(黑色在打印中起主要作用), 专门在CMY模型中加入了第4种颜色一一黑色, 从而得到CMYK影色模型. 这样当出版商说到“ 四色打印” 时, 即指CMY彩色模型的3种原色再加上黑色。
实验:RGB模型与CMY模型的相互转换:
(1)RGB → CMY:
转换公式:
代码实现:
def rgb_cmy(img):
r, g, b = cv2.split(img)
r = r / 255.0
g = g / 255.0
b = b / 255.0
c = 1 - r
m = 1 - g
y = 1 - b
result = cv2.merge((c, m, y)) # merge the channels
return result
处理结果:
(2)CMY → RGB:
转换公式:
代码实现:
def cmy_rgb(img):
c, m, y = cv2.split(img)
c = c / 255.0
m = m / 255.0
y = y / 255.0
r = 1 - c
g = 1 - m
b = 1 - y
result = cv2.merge((r, g, b)) # merge the channels
print(result)
return result
处理结果:
1.3 HSI彩色模型
HSI模型更符合人描述和解释颜色的方式,以色调(Hue)、饱和度(Saturation)和亮度(Intensity) 三个特征量来描述颜色。
- 色调(H):是色彩的基本属性,就是平常所说的颜色名称,如红色、黄色等;
- 饱和度S):是指色彩的纯度(纯光被白光稀释的程度),饱和度越高,颜色越鲜艳;
- 亮度(I):是一个主观的描述子,实际上不可测量,体现了无色的强度概念;
通常把色调和饱和度统称为色度,HSI模型将图像的亮度信息和色度信息分离,使得很多针对灰度图像的算法可直接作用在亮度图像上而不该变彩色图像的色度信息。
HSI模型确定的颜色空间如下:
实验 RGB模式到HSI模式的相互转换:
(1) RGB → HSI
转换公式:
代码实现:
def rgb2hsv(img):
h = img.shape[0]
w = img.shape[1]
H = np.zeros((h,w),np.float32)
S = np.zeros((h, w), np.float32)
V = np.zeros((h, w), np.float32)
r,g,b = cv2.split(img)
r, g, b = r/255.0, g/255.0, b/255.0
for i in range(0, h):
for j in range(0, w):
mx = max((b[i, j], g[i, j], r[i, j]))
mn = min((b[i, j], g[i, j], r[i, j]))
V[i, j] = mx
if V[i, j] == 0:
S[i, j] = 0
else:
S[i, j] = (V[i, j] - mn) / V[i, j]
if mx == mn:
H[i, j] = 0
elif V[i, j] == r[i, j]:
if g[i, j] >= b[i, j]:
H[i, j] = (60 * ((g[i, j]) - b[i, j]) / (V[i, j] - mn))
else:
H[i, j] = (60 * ((g[i, j]) - b[i, j]) / (V[i, j] - mn))+360
elif V[i, j] == g[i, j]:
H[i, j] = 60 * ((b[i, j]) - r[i, j]) / (V[i, j] - mn) + 120
elif V[i, j] == b[i, j]:
H[i, j] = 60 * ((r[i, j]) - g[i, j]) / (V[i, j] - mn) + 240
H[i,j] = H[i,j] / 2
return H, S, V
处理结果:
(2)HSI → RGB
转换公式:
代码实现:
def hsi_rgb(hsi_img):
img_rows = int(hsi_img.shape[0])
img_cols = int(hsi_img.shape[1])
H, S, I = cv2.split(hsi_img)
H = H / 255.0
S = S / 255.0
I = I / 255.0
bgr_img = hsi_img.copy()
B, G, R = cv2.split(bgr_img)
for i in range(img_rows):
for j in range(img_cols):
if S[i, j] < 1e-6:
R = I[i, j]
G = I[i, j]
B = I[i, j]
else:
H[i, j] *= 360
if H[i, j] > 0 and H[i, j] <= 120:
B = I[i, j] * (1 - S[i, j])
R = I[i, j] * (1 + (S[i, j] * math.cos(H[i, j] * math.pi / 180)) / math.cos((60 - H[i, j]) * math.pi / 180))
G = 3 * I[i, j] - (R + B)
elif H[i, j] > 120 and H[i, j] <= 240:
H[i, j] = H[i, j] - 120
R = I[i, j] * (1 - S[i, j])
G = I[i, j] * (1 + (S[i, j] * math.cos(H[i, j] * math.pi / 180)) / math.cos((60 - H[i, j]) * math.pi / 180))
B = 3 * I[i, j] - (R + G)
elif H[i, j] > 240 and H[i, j] <= 360:
H[i, j] = H[i, j] - 240
G = I[i, j] * (1 - S[i, j])
B = I[i, j] * (1 + (S[i, j] * math.cos(H[i, j] * math.pi / 180)) / math.cos((60 - H[i, j]) * math.pi / 180))
R = 3 * I[i, j] - (G + B)
bgr_img[i, j, 0] = B * 255
bgr_img[i, j, 1] = G * 255
bgr_img[i, j, 2] = R * 255
return bgr_img
处理结果:
1.4 HSV模型
HSV模型比HSI模型更与人类对颜色的感知接近。H代表色调,S代表饱和度,V代表亮度值。HSV模型的坐标系统可以是圆柱坐标系统,但一般用六棱锥来表示,HSV颜色空间的模型对应于圆柱坐标系中的一个圆锥形子集,圆锥的顶面对应于V=1。它包含RGB模型中的R=1,G=1,B=1三个面,所代表的颜色较亮。色彩H由绕V轴的旋转角给定。红色对应于角度0°,绿色对应于角度120°,蓝色对应于角度240°。在HSV颜色模型中,每一种颜色和它的补色相差180°。饱和度S取值从0到1,所以圆锥顶面的半径为1。与HSI模型比较相似。可以通过比较HSI、HSV与RGB空间的转换公式,来比较HSI与HSV的区别。
实验RGB与HSV的转换:
转换公式:
代码实现:
def rgb2hsv(img):
h = img.shape[0]
w = img.shape[1]
H = np.zeros((h,w),np.float32)
S = np.zeros((h, w), np.float32)
V = np.zeros((h, w), np.float32)
r,g,b = cv2.split(img)
r, g, b = r/255.0, g/255.0, b/255.0
for i in range(0, h):
for j in range(0, w):
mx = max((b[i, j], g[i, j], r[i, j]))
mn = min((b[i, j], g[i, j], r[i, j]))
V[i, j] = mx
if V[i, j] == 0:
S[i, j] = 0
else:
S[i, j] = (V[i, j] - mn) / V[i, j]
if mx == mn:
H[i, j] = 0
elif V[i, j] == r[i, j]:
if g[i, j] >= b[i, j]:
H[i, j] = (60 * ((g[i, j]) - b[i, j]) / (V[i, j] - mn))
else:
H[i, j] = (60 * ((g[i, j]) - b[i, j]) / (V[i, j] - mn))+360
elif V[i, j] == g[i, j]:
H[i, j] = 60 * ((b[i, j]) - r[i, j]) / (V[i, j] - mn) + 120
elif V[i, j] == b[i, j]:
H[i, j] = 60 * ((r[i, j]) - g[i, j]) / (V[i, j] - mn) + 240
H[i,j] = H[i,j] / 2
return H, S, V
处理结果:
1.5 YCbCr 彩色空间
YCbCr 彩色空间广泛用于数字视频。在这种格式中,亮度信息用单独的分量 Y来表示,彩色信息是用两个色差分量 Cb 和 Cr来存储的。分量 Cb 是蓝色分量与参考值的差,分量 Cr是红色分量与参考值的差。 RGB转换为 YcbCr 的转换是:
实验 RGB模式与YCbCr模式的相互转换:
(1)RGB → YCbCr
转换公式:
Y = 0.257*R+0.564*G+0.098*B+16
Cb = -0.148*R-0.291*G+0.439*B+128
Cr = 0.439*R-0.368*G-0.071*B+128
代码实现:
def rgb2ycbcr(rgb_image):
"""convert rgb into ycbcr"""
if len(rgb_image.shape)!=3 or rgb_image.shape[2]!=3:
raise ValueError("input image is not a rgb image")
rgb_image = rgb_image.astype(np.float32)
transform_matrix = np.array([[0.257, 0.564, 0.098],
[-0.148, -0.291, 0.439],
[0.439, -0.368, -0.071]])
shift_matrix = np.array([16, 128, 128])
ycbcr_image = np.zeros(shape=rgb_image.shape)
w, h, _ = rgb_image.shape
for i in range(w):
for j in range(h):
ycbcr_image[i, j, :] = np.dot(transform_matrix, rgb_image[i, j, :]) + shift_matrix
return ycbcr_image
处理结果:
(2)YCbCr → RGB
转换公式:
R = 1.164*(Y-16)+1.596*(Cr-128)
G = 1.164*(Y-16)-0.392*(Cb-128)-0.813*(Cr-128)
B = 1.164*(Y-16)+2.017*(Cb-128)
代码实现:
def ycbcr2rgb(ycbcr_image):
"""convert ycbcr into rgb"""
if len(ycbcr_image.shape)!=3 or ycbcr_image.shape[2]!=3:
raise ValueError("input image is not a rgb image")
ycbcr_image = ycbcr_image.astype(np.float32)
transform_matrix = np.array([[0.257, 0.564, 0.098],
[-0.148, -0.291, 0.439],
[0.439, -0.368, -0.071]])
transform_matrix_inv = np.linalg.inv(transform_matrix)
shift_matrix = np.array([16, 128, 128])
rgb_image = np.zeros(shape=ycbcr_image.shape)
w, h, _ = ycbcr_image.shape
for i in range(w):
for j in range(h):
rgb_image[i, j, :] = np.dot(transform_matrix_inv, ycbcr_image[i, j, :]) - np.dot(transform_matrix_inv, shift_matrix)
return rgb_image.astype(np.uint8)
处理结果:
(二)伪彩色图像处理
什么叫伪彩色图像处理?
也叫假彩色图像处理,根据一定的准则对灰度值赋以彩色的处理
区分:伪彩色图像、真彩色图像、单色图像
为什么需要伪彩色图像处理?
人类可以辨别上千种颜色和强度,但是只能辨别二十几种灰度
应用: 为人们观察和解释图像中的灰度目标
怎样进行伪彩色图像处理?强度分层法和灰度级-彩色变换法:
(1)强度分层法是伪彩色处理技术中最简单的一种。
在某个灰度级Li上设置一个平行于x-y平面的切割平面,切割平面下面的,即灰度级小于Li的像素分配给一种颜色,相应的切割平面上大于灰度级Li的像素分配给另一种颜色。这样切割结果可以分成两层的伪彩色。可以使用M个平面去切割,就会得到M个不同灰度级的区域,这样就是具有M种颜色的为彩色图像。这种方法虽然简单,但是视觉效果不理想。
(2)灰度级-彩色变换法可以将灰度图像变为具有多种颜色渐变的连续彩色图像。
主要就是将图像通过不同变换特性的红、绿、蓝3个变换器,然后将三个颜色通道的输出合成某种颜色。由于三种颜色变换的不同,使得不同大小灰度级可以合成不同的颜色。一组典型的变换传递函数如下图。
实验 灰度分层:
原图:
代码:
第一种方法,二值映射:
def slice_a(img):
h,w = img.shape[0],img.shape[1]
new_img = np.zeros((h,w))
for i in range(h):
for j in range(w):
if img[i,j] <190 or img[i,j]>230:
new_img[i, j] = 0
else:
new_img[i,j] = 255
return new_img
处理效果:
第二种方法,区域映射:
def slice_b(img):
h, w = img.shape[0], img.shape[1]
new_img = np.zeros((h, w))
for i in range(h):
for j in range(w):
if img[i, j] <= 230 and img[i, j] >= 190:
new_img[i, j] = 255
else:
new_img[i,j] = img[i,j]
return new_img
处理效果:
实验总结:两种方法处理的效果区别很大,二值映射处理只有黑白两色,对于轮廓的表现力比较强;区域映射处理后,对于整体图像的细节表现稍微好一点。在后期处理的不同要求不同目的考量下,选择合适的方式。
(三)全彩色图像处理及彩色变换
3.1 全彩色图像处理
通常,全彩色图像处理技术总的可以分为以下两大类:
(1)对3个平面分量单独处理,然后将分别处理过的3个分量合成彩色图像。对每个分量的处理技术可以应用到对灰度图像处理的技术上。但是这种通道式的独立处理技术忽略了通道间的相互影响。
(2)直接对彩色像素进行处理。因为全彩色图像至少有3个分量,彩色像素实际上是一个向量。直接处理就是同时对所有分量进行无差别的处理.这时彩色图像的 3个分量用向量形式表示,即对彩色图像上任一点的像素 c(x,y),有:
3.2 彩色变换
彩色变换主要涉及在单一色彩模型内处理彩色图像的分量,而不是这些分量在不同模型间的转换。
彩色变换函数:
f(x,y)是彩色输入图像
g(x,y)是变换或处理过的彩色输出图像
T 是在空间邻域(x,y)上对f 的操作
彩色变换的简单形式:
ri 和si是和在任何点处彩色分量的变量
T1,T2 ,...Tn 是一个对ri操作产生si的变换或彩色映射函数集
选择的彩色空间决定n的值,如RGB彩色空间,n=3,r1,r2和r3表示红、绿、蓝分量;CMYK,则n=4
补色:在如图所示的彩色环上,与一种色调直接相对立的另一种色调称为补色
作用:增强嵌在彩色图像暗区的细节
补色公式:max(r,g,b)+min(r,g,b)-[r,g,b]
补色实验:
python实现:
def bu(img):
height, width, channels = img.shape
buImg=img.copy()
for i in range(height):
for j in range(width):
buImg[i,j]=(img[i][j].max()+img[i][j].min())-img[i][j]
return buImg
原图:
补色处理后:
灰度图像处理后视觉上无区别,换彩色图像试试,由于原图的彩色图像过大,处理过程中出现了一些问题,现在换一张试试看:
原图:
补色处理后:
实验结果分析:补色对于增强嵌在彩色图像暗区的细节很有用,特别是在区域在大小上占优势时。
3.4 彩色图像的直方图处理
彩色图是没有直方图的,只能分别在R、G、B方向分别求直方图再合并一下。
实验彩色直方图处理:
利用OpenCV获取彩色图像,利用split方法区分三原色,具体代码如下:
import cv2
import numpy as np
img = cv2.imread('image0.jpg', 1)
channels = cv2.split(img)
图像颜色分离后也就获得了B,G,R三个颜色通道,接下来就可以调用绘制直方图的方法了。
计算并绘制直方图,将获取的三个通道分别作为参数传入绘制直方图方法中,代码如下:
for i in range(0, 3):
imageHist(channels[i], i + 31)
当i值分别为0,1,2的时候,对应的就是B,G,R三个颜色通道。将i+31作为参数为了在方法中可以判断出传入的是哪个通道,代码如下:
def imageHist(img, type):
# color = (255, 255, 255)
if type == 31:
color = (255, 0, 0)
windowName = 'B Hist'
elif type == 32:
color = (0, 255, 0)
windowName = 'G Hist'
elif type == 33:
color = (0, 0, 255)
windowName = 'R Hist'
接下来就可以计算并显示直方图了,具体代码如下:
Hist = cv2.calcHist([img], [0], None, [256], [0.0, 255.0])
minV, maxV, minL, MaxL = cv2.minMaxLoc(Hist)
HistImage = np.zeros([256, 256, 3], np.uint8)
for h in range(256):
intenormal = int(Hist[h] * 256 / maxV)
cv2.line(HistImage, (h, 256), (h, 256 - intenormal), color) # 绘制直方图
cv2.imshow(windowName, HistImage)
return HistImage
处理结果:
3.5 彩色直方图均衡化
彩色图像直方图均衡化:在已知灰度直方图均衡化的方法后,但是通过分别用于图像RGB颜色值的红色、绿色和蓝色分量,从而也可以对彩色图像进行处理。实际上,对彩色分量rgb分别做均衡化,会产生奇异的点,图像不和谐。一般采用的是用YUV空间进行亮度的均衡即可。此次学习采用的是将图像由RGB色彩空间到HSI的变换,然后在亮度通道上进行直方图均衡化;均衡化原理同灰度图像。
HSI模型<->RGB模型
HSI颜色模型是一个满足计算机数字化颜色管理需要的高度抽象模拟的数学模型。HSI模型是从人的视觉系统出发,直接使用颜色三要素–色调(Hue)、饱和度(Saturation)和亮度(Intensity,有时也翻译作密度或灰度)来描述颜色。
RGB向HSI模型的转换是由一个基于笛卡尔直角坐标系的单位立方体向基于圆柱极坐标的双锥体的转换。基本要求是将RGB中的亮度因素分离,通常将色调和饱和度统称为色度,用来表示颜色的类别与深浅程度。在图中圆锥中间的横截面圆就是色度圆,而圆锥向上或向下延伸的便是亮度分量的表示。
从RGB空间到HSI空间的转换公式见上。
彩色图像直方图均衡化实验:
直方图:
首先获取HSI空间:
def hsi_rgb(hsi_image):
rows = np.shape(hsi_image)[0]
cols = np.shape(hsi_image)[1]
rgb_image = hsi_image.copy()
# 对图像进行通道拆分
hsi_h = hsi_image[:, :, 0]
hsi_s = hsi_image[:, :, 1]
hsi_i = hsi_image[:, :, 2]
# 把通道归一化到[0,1]
hsi_h = hsi_h / 255.0
hsi_s = hsi_s / 255.0
hsi_i = hsi_i / 255.0
B, G, R = hsi_h, hsi_s, hsi_i
for i in range(rows):
for j in range(cols):
hsi_h[i, j] *= 360
if 0 <= hsi_h[i, j] < 120:
B = hsi_i[i, j] * (1 - hsi_s[i, j])
R = hsi_i[i, j] * (1 + (hsi_s[i, j] * np.cos(hsi_h[i, j] * np.pi / 180)) / np.cos(
(60 - hsi_h[i, j]) * np.pi / 180))
G = 3 * hsi_i[i, j] - (R + B)
elif 120 <= hsi_h[i, j] < 240:
hsi_h[i, j] = hsi_h[i, j] - 120
R = hsi_i[i, j] * (1 - hsi_s[i, j])
G = hsi_i[i, j] * (1 + (hsi_s[i, j] * np.cos(hsi_h[i, j] * np.pi / 180)) / np.cos(
(60 - hsi_h[i, j]) * np.pi / 180))
B = 3 * hsi_i[i, j] - (R + G)
elif 240 <= hsi_h[i, j] <= 300:
hsi_h[i, j] = hsi_h[i, j] - 240
G = hsi_i[i, j] * (1 - hsi_s[i, j])
B = hsi_i[i, j] * (1 + (hsi_s[i, j] * np.cos(hsi_h[i, j] * np.pi / 180)) / np.cos(
(60 - hsi_h[i, j]) * np.pi / 180))
R = 3 * hsi_i[i, j] - (G + B)
rgb_image[i, j, 0] = B * 255
rgb_image[i, j, 1] = G * 255
rgb_image[i, j, 2] = R * 255
return rgb_image
处理效果:
然后RGB转HSI:
hsi_image = rgb_hsi(rgb_image)
cv2.imshow('hsi_image', hsi_image)
cv2.imwrite('D:/Data/hsi_result.png', hsi_image)
接着HSI在亮度分量上均衡化
histogram_1 = draw_histogram(hsi_image)
lut = np.zeros(256, dtype=hsi_image.dtype)
result = histogram_equalization(histogram_1, lut, hsi_image) # 均衡化处理
cv2.imshow('his_color_image', result)
处理效果:
再HSI转RGB:
image_equ = cv2.imread(r'D:/Data\his_color.png') # 读取图像
rgb_result = hsi_rgb(image_equ)
最终处理效果:
直方图:
在有了上面的处理过程后,利用直方图均衡化来针对图像观感进行改善:
python实现:
# 全局直方图均衡化
def hisEqulColor1(img):
image_yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
image_yuv[:, :, 0] = cv2.equalizeHist(image_yuv[:, :, 0])
img = cv2.cvtColor(image_yuv, cv2.COLOR_YUV2BGR)
return img
# 自适应直方图均衡化
def hisEqulColor2(img):
image_yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
clahe.apply(image_yuv[:, :, 0])
img = cv2.cvtColor(image_yuv, cv2.COLOR_YUV2BGR)
return img
处理效果:原图,全局均衡化,自适应均衡化
实验结果分析:在图像整体情况较亮的情况下,采用全局均衡化可以取得较好的效果;
在图像整体较暗的情况下,采用自适应均衡化的效果明显好于全局均衡化。
(四)彩色图像的平滑和锐化
4.1 平滑处理
也称 模糊处理” ,使用频率很高的图像处理方法。平滑处理的用途有很多,最常见的是用来减少图像上的噪点或者失真。在涉及到降低图像分辨率时,平滑处理是非常好用的方法。
对灰度图像进行平滑的文章详见之前写的第三章图像学习笔记:数字图像处理学习笔记 三 灰度变换与空间滤波这些算法在彩色图像中应用有两种,一种是对RGB全部分量进行分别处理,然后将个处理过的分量进行合并,得到彩色图像。另一种是对HSI的I分量进行处理,同样能得到平滑效果 。
实验双边平滑滤波:
双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的。具有简单、非迭代、局部的特点。
- 优点:双边滤波器的好处是可以做边缘保存(edge preserving),一般过去用的维纳滤波或者高斯滤波去降噪,都会较明显地模糊边缘,对于高频细节的保护效果并不明显。 双边滤波器顾名思义比高斯滤波多了一个高斯方差sigma-d ,它是基于空间分布的高斯滤波函数,所以在边缘附近,离的较远的像素不会太多影响到边缘上的像素值,这样就保证了边缘附近像素值的保存。但是由于保存了过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能够干净的滤掉,只能够对于低频信息进行较好的滤波。
- 对比:高斯滤波器只考虑像素之间的空 间关系,而不会考虑像素值之间的关系(像素的相似度)。所以这种方法不会考虑一个像素是否位于边界。因此边界也会别模糊掉。
双边滤波在同时使用空间高斯权重和灰度值相似性高斯权重。空间高斯函数确保只有邻近区域的像素对中心点有影响,灰度值相似性高斯函数确保只有与中心像素灰度值相近的才会被用来做模糊运算。所以这种方法会确保边界不会被模糊掉,因为边界处的灰度值变化比较大。
代码实现:
img = cv2.imread('D:/Data/school.jpg')
blured = np.hstack([
cv2.bilateralFilter(img, 9, 5, 5),
cv2.bilateralFilter(img, 9, 100, 100),
cv2.bilateralFilter(img, 9, 50, 50)
])
plt.figure(figsize=(20, 10))
取不同滤波器窗口大小处理效果:
实验分析:不同大小的滤波器处理效果有差别,在选取到合适大小的滤波器窗口的时候,可以尽可能地去除噪声,平滑图像,使得图像显示更为均匀,边界更为清晰。
4.2 锐化处理
图像锐化是和平滑相反的操作,目的是为了使模糊的图像变得清晰。既然是相反的目的,那么操作应该也是相反的,平滑使用的是图像邻域的加权求和或者是积分运算,而锐化则是使用求导数(梯度)或有限差分来实现。
锐化原理的介绍详见:数字图像处理学习笔记 三 灰度变换与空间滤波
基于拉普拉斯变化的锐化实验:
定义不同的卷积核:shapen1
kernel_sharpen_1 = np.array([
[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]])
卷积:
output_1 = cv2.filter2D(image, -1, kernel_sharpen_1)
实现:
cv2.imshow('Original Image', image)
cv2.imshow('sharpen_1 Image', output_1)
处理效果:
kernel_sharpen_2 = np.array([
[1, 1, 1],
[1, -7, 1],
[1, 1, 1]])
处理效果:
定义不同的卷积核:shapen3
kernel_sharpen_3 = np.array([
[-1, -1, -1, -1, -1],
[-1, 2, 2, 2, -1],
[-1, 2, 8, 2, -1],
[-1, 2, 2, 2, -1],
[-1, -1, -1, -1, -1]]) / 8.0
处理效果:
实验结果分析:锐化处理将突出分量突变的区域,加重描绘图像中的物体边缘轮廓;同时不同大小的卷积核所突出的程度不同,应该根据需求合理选择。
(五)彩色图像的分割
彩色空间分割是基于单色图像(灰度图)分割技术在不同颜色通道上实现的。灰度图分割技术常见的有:直方图阀值化、特征聚类、边缘检测、基于区域的、模糊技术、神经网络等。
图像分割有公式化的定义(查文献)。图像分割本质上是一个心理学感知的问题,不会纯粹受分割方法不同的影响。灰度图的分割方法都是基于区域像素的非连续性或相似性。基于非连续性的方法主要是为了检测孤立的点、边缘、线(灰度突然变化的地方)。基于相似性的方法包括阀值、聚类、区域分割合并等。
色彩空间的转换都是对RGB三原色的线性和非线性的变换,RGB、HIS、LUV、CIE。RGB三原色定理(比色法)使其成为最广泛使用的模型,便于显示颜色(应用于电视,数码相机等),但是由于其RGB具有很高的相关性,所以不便于颜色的分割和分析,并且RGB空间无法衡量两个颜色的相似性。YIQ(美国)、YUV(欧洲),是两种电视色彩信号编码的空间,是在RGB空间上的两种线性变换。HSI(hue-saturation-intensity)是另一种常用的颜色空间,因为它与人类的视觉较相近,还有一些HSI的变种,HSB、HSV、HSL。色调表示基础的颜色,是光线频谱中的峰值(主分量),饱和度表示颜色的纯度,即白光混合在基础颜色中的比例。人类的视觉系统可以轻易的辨别出色调,但是对光照和饱和度的辨别却不包含颜色的信息,HSI真是表达了这样一种颜色空间。当使用灰度级的算法时,可以使用I分量,当做物体识别时,可以使用H分量。在处理非一致光照条件下(有阴影)图片时,这种方法特别有效,因为H分量与光照无关。如果使用RGB空间则不行,因为光照、色调、饱和度都编码在了R、G、B中无法分割了。缺点是在色彩空间的极限奇异坐标(圆柱表面)上不稳定。基于物理特性的模型考虑了对象的对光照的反射率,折射率等物理因素,有利于做图像理解。很多学者提议使用线性色彩空间,但是线性空间中三个基础元素的相关性高,且做图像处理时需在3D空间内。相比较,非线性空间就具有较大的优势,只需在1D上处理,虽然存在奇异点不稳定的问题。
人类能够识别上千种的颜色和光强,但是只能识别24种灰度。很多时候依靠灰度信息无法提取图像,但是颜色却可以。颜色提供了除光强外更多的信息。彩色图片的分割基本都是基于单色图片的技术 。
5.1 基于HSI的彩色图像分割
实验代码:
def color_seperate(image):
hsi = cv.cvtColor(image, cv.COLOR_BGR2HSV) #对目标图像进行色彩空间转换
lower_hsi = np.array([100, 43, 46])
upper_hsi = np.array([124, 255, 255])
mask = cv.inRange(hsv, lowerb=lower_hsv, upperb=upper_hsv)
dst = cv.bitwise_and(src, src, mask=mask)
cv.imshow('result', dst) #输出
处理效果:
实验结果分析:对整体较亮的图像处理后,结果分离出了物体的大致轮廓,同时似乎对蓝色较为敏感;在明暗区分明显的区域,分离效果也没有那么理想,细节处处理的很不好。
下面拓展一种处理效果稍好的K-Means聚类对比分割彩色图像方法。
5.2 K-Means聚类对比分割彩色图像
K-Means聚类是最常用的聚类算法,最初起源于信号处理,其目标是将数据点划分为K个类簇,找到每个簇的中心并使其度量最小化。该算法的最大优点是简单、便于理解,运算速度较快,缺点是只能应用于连续型数据,并且要在聚类前指定聚集的类簇数。
下面是K-Means聚类算法的分析流程,步骤如下
- 第一步,确定K值,即将数据集聚集成K个类簇或小组。
- 第二步,从数据集中随机选择K个数据点作为质心(Centroid)或数据中心。
- 第三步,分别计算每个点到每个质心之间的距离,并将每个点划分到离最近质心的小组,跟定了那个质心。
- 第四步,当每个质心都聚集了一些点后,重新定义算法选出新的质心。
- 第五步,比较新的质心和老的质心,如果新质心和老质心之间的距离小于某一个阈值,则表示重新计算的质心位置变化不大,收敛稳定,则认为聚类已经达到了期望的结果,算法终止。
- 第六步,如果新的质心和老的质心变化很大,即距离大于阈值,则继续迭代执行第三步到第五步,直到算法终止。
实验步骤:
- 建立工程并导入sklearn包
- 加载图片并进行预处理
- 加载Kmeans聚类算法,设置不同的K值
- 对像素点进行聚类并输出
python实验代码:
data = img.reshape((-1,3))
data = np.float32(data)
criteria = (cv2.TERM_CRITERIA_EPS +
cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
#设置标签
flags = cv2.KMEANS_RANDOM_CENTERS
#K-Means聚类 聚集成2类
compactness, labels2, centers2 = cv2.kmeans(data, 2, None, criteria, 10, flags)
#K-Means聚类 聚集成4类
compactness, labels4, centers4 = cv2.kmeans(data, 4, None, criteria, 10, flags)
#K-Means聚类 聚集成8类
compactness, labels8, centers8 = cv2.kmeans(data, 8, None, criteria, 10, flags)
#K-Means聚类 聚集成16类
compactness, labels16, centers16 = cv2.kmeans(data, 16, None, criteria, 10, flags)
#K-Means聚类 聚集成64类
compactness, labels64, centers64 = cv2.kmeans(data, 64, None, criteria, 10, flags)
centers2 = np.uint8(centers2)
res = centers2[labels2.flatten()]
dst2 = res.reshape((img.shape))
centers4 = np.uint8(centers4)
res = centers4[labels4.flatten()]
dst4 = res.reshape((img.shape))
centers8 = np.uint8(centers8)
res = centers8[labels8.flatten()]
dst8 = res.reshape((img.shape))
centers16 = np.uint8(centers16)
res = centers16[labels16.flatten()]
dst16 = res.reshape((img.shape))
centers64 = np.uint8(centers64)
res = centers64[labels64.flatten()]
dst64 = res.reshape((img.shape))
实验结果:
实验结果分析:效果比HSI彩色空间的分割好,通过设置不同的k值,能够得到不同的聚类结果。同时,k值的不确定也是Kmeans算法的一个缺点。往往为了达到好的实验结果,需要进行多次尝试才能够选取最优的k值。而像层次聚类的算法,就无需指定k值,只要给定限制条件,就能自动地得到类别数k。
5.3 彩色边缘检测
在图像识别中,需要有边缘鲜明的图像,即图像锐化。图像锐化的目的是为了突出图像的边缘信息,加强图像的轮廓特征,以便于人眼的观察和机器识别。图像边缘检测大幅度地减少了数据量,并且剔除了可以认为不相关的信息,保留了图像重要的结构属性。有许多方法用于边缘检测,它们的绝大部分可以划分为两类:基于查找一类和基于零穿越的一类。基于查找的方法通过寻找图像一阶导数中的最大值和最小值来检测边界,通常是将边界定位在梯度最大的方向。基于零穿越的方法通过寻找图像二阶导数零穿越来寻找边界,通常是Laplacian过零点或者非线性差分表示的过零点。
如果将边缘认为是一定数量点亮度发生变化的地方,那么边缘检测大体上就是计算这个亮度变化的导数。
(1)检测方法
边缘检测的方法大致可分为两类:基于搜索和基于零交叉
- 基于搜索的边缘检测方法首先计算边缘强度,通常用一阶导数表示,例如梯度模,然后,用计算估计边缘的局部方向,通常采用梯度的方向,并利用此方向找到局部梯度模的最大值。
- 基于零交叉的方法找到由图像得到的二阶导数的零交叉点来定位边缘,通常用拉普拉斯算子或非线性微分方程的零交叉点。滤波作为边缘检测的预处理通常是必要的,通常采用高斯滤波。
(2)Canny算子边缘检测实验
图像边缘检测必须满足两个条件,一能有效地抑制噪声;二必须尽量精确确定边缘的位置。
根据对信噪比与定位乘积进行测度,得到最优化逼近算子。这就是Canny边缘检测算子。
算法的基本步骤为:
1.用高斯滤波器平滑图像;
2.用一阶偏导的有限差分来计算梯度的幅值和方向;
3.对梯度幅值进行非极大抑制;
4.用双阈值算法检测和连接边缘。
代码实现:
# canny算子
img = cv2.imread('luotuo.jpg', 0)
blur = cv2.GaussianBlur(img, (3, 3), 0)
canny = cv2.Canny(blur, 50, 150)
cv2.imshow('canny', canny)
cv2.waitKey(0)
cv2.destroyAllWindows()
处理效果:
实验结果分析:对图像的处理效果还是比较不错的,在阈值的选取上要合适。