Opencv_100问_第一章 (1-5)

文章目录

      • 一. 通道交换
        • ① Opencv中的通道顺序
        • ② 通道交换的代码示例
      • 二. 灰度化
      • 三. 二值化(Thresholding)
      • 四. 大律法进行二值化(Otsu' Method)
        • ① 大律法简介
        • ② 计算方法
        • ③ 代码实现
      • 五. RGB和HSV的转换
        • ① HSV模型简介
        • ② RGB转换为HSV
        • ③ HSV转换为BGR

一. 通道交换

① Opencv中的通道顺序

  1. Opencv中的通道顺序是BGR的顺序
  2. Python中图像的保存格式是Numpy的形式,也就是ndarray的格式
  3. 当读取彩色的图像的时候,每个像素的位置是一个三元组. (b1,g1,r1) = image[i,j]
  4. 所以一幅图像的各个通道的分量表示为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)

三. 二值化(Thresholding)

  1. 图像二值化的概念和思想就是把图像转换为只有0,和255两种颜色的表示方法.
  2. 比如,使用128来进行二值化,当亮度大于或者等于128的时候,设置为255,当小于128的时候设置为0
  3. ndarry的区域操作方式,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’ Method)

① 大律法简介

  1. 大律法(又叫最大类间方差法)是一种全局的自适应阈值确定的方法,简称为OTSU
  2. 它是一种基于全局的二值化算法,它是根据图像的灰度特性,将图像分成前景和背景两个部分.当取最佳阈值时,两部分之间的差别应该是最大的,在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)

结果:
Opencv_100问_第一章 (1-5)_第1张图片

五. RGB和HSV的转换

① HSV模型简介

HSV颜色模型是根据颜色的直观特征所创立的一种颜色模型,它的名字就代表了这个模型的三个参数H,S,V。模型为六棱锥,三个参数就在上面不同维度进行表示。模型如下。原图来源百度百科。前者是空间模型,后者是模型概念图

Opencv_100问_第一章 (1-5)_第2张图片

  • 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为白色.

Opencv_100问_第一章 (1-5)_第3张图片
两者之间具有密切的关联,当RGB的模型沿着原点的对角线,即黑色点与白色点的连线为垂线轴观察就会转换至HSV的模型.

② 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

HSV转换为BGR的方式

Opencv_100问_第一章 (1-5)_第4张图片
代码实现:

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

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