Opencv
中的通道顺序是BGR
的顺序- 在
Python
中图像的保存格式是Numpy
的形式,也就是ndarray
的格式- 当读取彩色的图像的时候,每个像素的位置是一个三元组.
(b1,g1,r1) = image[i,j]
- 所以一幅图像的各个通道的分量表示为
B,G,R = image[:,:,0], image[:,;,1], image[:,:,2]
# @Time : 2022/6/7 16:27
# @Author : Fioman
# @Phone : 13149920693
# @Tips : Talk is Cheap,Show me the code! ^_^^_^
from settings import *
def BGR_to_RGB(image):
"""
将BGR通道的图像,转换为RGB格式的.
:param image:
:return:
"""
B = image[:, :, 0]
G = image[:, :, 1]
R = image[:, :, 2]
newImage = image.copy()
newImage[:, :, 0] = R
newImage[:, :, 1] = G
newImage[:, :, 2] = B
return newImage
def split_image_to_BGR(image):
"""
将图像拆分成B,G,R通道.
:param image:
:return:
"""
imageB = np.zeros(image.shape, dtype=np.uint8)
imageG = imageB.copy()
imageR = imageB.copy()
imageB[:,:,0] = image[:,:,0]
imageG[:,:,1] = image[:,:,1]
imageR[:,:,2] = image[:,:,2]
return imageB,imageG,imageR
if __name__ == '__main__':
imagePath = os.path.join(OPENCV_100_Q_PATH, "color_02.bmp")
imageOriginal = cv.imread(imagePath, cv.IMREAD_COLOR)
imageRgb = BGR_to_RGB(imageOriginal)
cv.imshow("OriginalBgr", imageOriginal)
cv.imshow("RgbOut", imageRgb)
B, G, R = split_image_to_BGR(imageOriginal)
cv.imshow("B", B)
cv.imshow("G", G)
cv.imshow("R", R)
cv.waitKey(0)
图像灰度化,图像灰度是一种图像亮度的表示方法,通过下面的方式计算:
按照这个公式把图像灰度化,图像灰度化就是计算各个分量的权重,然后重新计算灰度值
Y = 0.2126 * R + 0.7152 * G + 0.0722 * B
其中的R和G和B
可以是ndarray
,使用矢量计算法,可以进行计算.
# @Time : 2022/6/7 16:52
# @Author : Fioman
# @Phone : 13149920693
# @Tips : Talk is Cheap,Show me the code! ^_^^_^
from settings import *
imagePath = os.path.join(OPENCV_100_Q_PATH, "color_02.bmp")
def BGR_to_gray(image):
"""
将BGR通道的彩色图像,转换为灰度图像,根据一般的权重公式进行转换
:param image:
:return:
"""
B = image[:, :, 0]
G = image[:, :, 1]
R = image[:, :, 2]
imageNew = 0.2126 * R + 0.7152 * G + 0.0722 * B
imageNew = imageNew.astype(np.uint8)
return imageNew
if __name__ == '__main__':
image = cv.imread(imagePath,cv.IMREAD_COLOR)
gray = BGR_to_gray(image)
cv.imshow("Original",image)
cv.imshow("Gray",gray)
cv.waitKey(0)
- 图像二值化的概念和思想就是把图像转换为只有0,和255两种颜色的表示方法.
- 比如,使用
128
来进行二值化,当亮度大于或者等于128
的时候,设置为255
,当小于128
的时候设置为0ndarry
的区域操作方式,array[array 将array中满足
array的地方赋值为0.
array[array>=a] = 255
,将array
中满足条件>=a
的地方赋值为255
# @Time : 2022/6/7 17:05
# @Author : Fioman
# @Phone : 13149920693
# @Tips : Talk is Cheap,Show me the code! ^_^^_^
from settings import *
def BGR_to_Gray(image):
"""
将彩色图像转换为灰度图像.
:param image:彩色图像
:return:
"""
B = image[:, :, 0].copy()
G = image[:, :, 1].copy()
R = image[:, :, 2].copy()
grayImage = R * 0.2126 + G * 0.7152 + B * 0.0722
grayImage = grayImage.astype(np.uint8)
return grayImage
def binarization(image,thres=128):
newImage = image.copy()
newImage[newImage < thres] = 0
newImage[newImage >= thres] = 255
return newImage
if __name__ == '__main__':
imagePath = os.path.join(OPENCV_100_Q_PATH,"color_02.bmp")
image = cv.imread(imagePath,cv.IMREAD_COLOR)
imageGray = BGR_to_Gray(image)
imageBinary = binarization(imageGray)
cv.imshow("Original",image)
cv.imshow("Gray",imageGray)
cv.imshow("Binary_128",imageBinary)
cv.waitKey(0)
- 大律法(又叫最大类间方差法)是一种全局的自适应阈值确定的方法,简称为
OTSU
- 它是一种基于全局的二值化算法,它是根据图像的灰度特性,将图像分成前景和背景两个部分.当取最佳阈值时,两部分之间的差别应该是最大的,在
OTSU
算法中所采用的衡量差别的标准就是较为常见的最大类间方差.
最大类间方差采用穷举的方式(0-255),找到使得
intra-class variance
最小的鱼子处理步骤如下:
图像大小M * N
1) 初始化一阈值T,将图像(x,y)的值分为两类 A 和 B
2) N0为灰度小于T的像素的个数,N0的平均灰度为u0
3) N1为灰度大于等于T的像素的个数,N1的平均灰度为u1
4) w0 = N0 / (M * N)
// 落在N0的概率 ①5) w1 = N1 / (M * N)
// 落在N1的概率 ②6) N0 +N1 = M*N;
③7) w0 + w1 = 1;
④8) u = w0*u0 + w1*u1
⑤ 平均灰度期望值9) g = w0(u0 -u)^2 + w1(u1 - u)^2
⑥ 最大类间方差公式10) 将4和5带入到6中,就可以得到最大类间方差公式: g = w0w1(u0-u1)^2
然后就是遍历T,取得使g最大的值,记录这时T就是最佳的阈值.
# @Time : 2022/6/8 11:48
# @Author : Fioman
# @Phone : 13149920693
# @Tips : Talk is Cheap,Show me the code! ^_^^_^
from settings import *
def BGR_to_Gray(image):
"""
将BGR通道的彩色图像转换为灰度图像
:param image:
:return:
"""
B = image[:, :, 0].copy()
G = image[:, :, 1].copy()
R = image[:, :, 2].copy()
grayImage = 0.2126 * R + 0.7252 * G + 0.0722 * B
grayImage = grayImage.astype(np.uint8)
return grayImage
# Otsu Binarization
def otsu_binarization(image, T=128):
maxSigma = 0 # 最大类间方差
maxVal = 0 # 最大类间方差对应的阈值
h, w = image.shape[:2]
for _t in range(1, 256):
w0 = image[np.where(image < _t)]
w1 = image[np.where(image >= _t)]
u0 = np.mean(w0) if len(w0) > 0 else 0
u1 = np.mean(w1) if len(w1) > 0 else 0
w0 = len(w0) / (w * h)
w1 = len(w1) / (w * h)
sigma = w0 * w1 * ((u0 - u1) ** 2)
if sigma > maxSigma:
maxSigma = sigma
maxVal = _t
print("Threshold = ", maxVal)
T = maxVal
imageNew = image.copy()
imageNew[imageNew < T] = 0
imageNew[imageNew >= T] = 255
return imageNew
if __name__ == '__main__':
imagePath = os.path.join(OPENCV_100_Q_PATH,"color_03.bmp")
imageSrc = cv.imread(imagePath,cv.IMREAD_COLOR)
cv.imshow("ImageOriginal",imageSrc)
cv.waitKey(0)
imageGray = BGR_to_Gray(imageSrc)
cv.imshow("ImageGray",imageGray)
thresOtsu = otsu_binarization(imageGray,128)
cv.imshow("ThresOtsu",thresOtsu)
cv.waitKey(0)
HSV颜色模型是根据颜色的直观特征所创立的一种颜色模型,它的名字就代表了这个模型的三个参数H,S,V。模型为六棱锥,三个参数就在上面不同维度进行表示。模型如下。原图来源百度百科。前者是空间模型,后者是模型概念图
H(Hue):
色调. 采用角度表示,在模型中为棱锥的底面,因此范围就是0~360度,如图所示,不同的角度规定了不同的颜色.0度表示红色,每隔120度分别为绿色和蓝色,对应三基色RGB,它们两两之间又以60度为间隔加入互补色,由0度逆时针开始分别为黄色,青色和品红色(紫色).
S(Saturation):
饱和度. 定义为接近光谱色的程度.取值范围是0~1(图片为LPL_DEPTH_32F类型),或者(0-255)(图片为LPL_DEPTH_8UC类型),饱和度越高颜色越深,白色的饱和度为0.
V(Value):
明度. 颜色的明暗程度,范围为0-1,0为黑色,1为白色.图片类型不同的情况同S
;
RGB模型为三维立体图,模型如下所示:每个维度的取值范围是0~255,0为黑色,255为白色.
两者之间具有密切的关联,当RGB
的模型沿着原点的对角线,即黑色点与白色点的连线为垂线轴观察就会转换至HSV
的模型.
RGB->HSV的转换关系如下:
max = max(R,G,B)
min = min(R,G,B)
H = 0 (max == min)
H = 60 * (G-R) / (max-min) + 60 (min = B)
H = 60 * (B-G) / (max -min) + 180 (min = R)
H = 60 * (R-B) / (max - min) + 300 (min = G)
S = Max - Min
V = Max
代码实现
# @Time : 2022/6/9 10:16
# @Author : Fioman
# @Phone : 13149920693
# @Tips : Talk is Cheap,Show me the code! ^_^^_^
from settings import *
# BGR -> HSV
def BGR_to_HSV(image):
"""
将BGR彩色通道的图像转换为HSV通道的图像
:param image:
:return:
"""
img = image.copy() / 255.
hsv = np.zeros_like(img, dtype=np.float32)
# get max and min
maxVal = np.max(img, axis=2).copy()
minVal = np.min(img, axis=2).copy()
minArgs = np.argmin(img, axis=2)
# H min = max
hsv[...,0][np.where(maxVal == minVal)] = 0
## if min == B
ind = np.where((minArgs == 0) & (maxVal != minVal))
hsv[...,0][ind] = 60 * (img[...,1][ind] - img[...,2][ind]) / (maxVal[ind] - minVal[ind]) + 60
## if min == R
ind = np.where((minArgs == 2) & (maxVal != minVal))
hsv[...,0][ind] = 60 * (img[...,2][ind] - img[...,0][ind]) / (maxVal[ind] - minVal[ind]) + 180
## if min == G
ind = np.where((minArgs == 1) & (maxVal != minVal))
hsv[...,0][ind] = 60 * (img[...,2][ind] - img[...,0][ind]) / (maxVal[ind] - minVal[ind]) + 300
# S
hsv[...,1] = maxVal.copy() - minVal.copy()
# V
hsv[...,2] = maxVal.copy()
return hsv
if __name__ == '__main__':
imagePath = os.path.join(OPENCV_100_Q_PATH,"color_01.bmp")
imageOriginal = cv.imread(imagePath,cv.IMREAD_COLOR)
cv.imshow("Original",imageOriginal)
imageHsv = BGR_to_HSV(imageOriginal)
# Transpose Hue
imageHsv[...,0] = (imageHsv[...,0] + 180) % 360
cv.imshow("Hsv",imageHsv)
cv.waitKey(0)
HSV转换为BGR的方式
def HSV_to_BGR(image,hsv):
"""
将HSV格式的图片,转换为BGR格式的
:param image:
:return:
"""
img = image.copy() / 255.
# get max and min
maxVal = np.max(img,axis=2).copy()
minVal = np.min(img,axis=2).copy()
out = np.zeros_like(img)
H = hsv[..., 0]
S = hsv[..., 1]
V = hsv[..., 2]
C = S
H_ = H / 60.
X = C * (1 - np.abs(H_ % 2 - 1))
Z = np.zeros_like(H)
vals = [[Z, X, C], [Z, C, X], [X, C, Z], [C, X, Z], [C, Z, X], [X, Z, C]]
for i in range(6):
ind = np.where((i <= H_) & (H_ < (i + 1)))
out[..., 0][ind] = (V - C)[ind] + vals[i][0][ind]
out[..., 1][ind] = (V - C)[ind] + vals[i][1][ind]
out[..., 2][ind] = (V - C)[ind] + vals[i][2][ind]
out[np.where(maxVal == minVal)] = 0
out = np.clip(out, 0, 1)
out = (out * 255).astype(np.uint8)
return out