在一般的视觉视觉颜色是由RGB组成的,为了简化处理的视觉的复杂度,以及得到分割出指定物体的特征形状,通过二值化的方法更加的高效方便

二值化图像

  • 二值化定义:图像的二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果

  • 二值化分割定义:一幅图像包括目标物体、背景还有噪声,要想从多值的数字图像中直接提取出目标物体,常用的方法就是设定一个阈值T,用T将图像的数据分成两部分:大于T的像素群和小于T的像素群。这是研究灰度变换的最特殊的方法,称为图像的二值化(Binarization)。


重要的函数讲解

1.简单的阈值-(全局阈值):cv2.threshold(src, thresh, maxval, type, dst=None)->retval,dst

参数:

  • src: 指原图像,原图像应该是灰度图

  • thresh:二值化的阈值

  • maxval:超过thresh的像素值设置的最大值

  • type:二值化的方法操作

1)二进制阈值化 THRESH_BINARY

2.反二进制阈值化THRESH_BINARY_INV
3)截断阈值化 THRESH_TRUNC

4.阈值化为0 THRESH_TOZERO

5.反阈值化为0 THRESH_TOZERO_INV

6)大津阈值算法(OTSU):
简介:大津法(OTSU)可以根据图像特性,选择最佳的阈值,不需要人为提供阈值,故它也被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响。从大津法的原理上来讲,该方法又称作最大类间方差法,按照大津法求得的阈值进行图像二值化分割后,前景与背景图像的类间方差最大。适合处理所需提取的前景图像和背景图像差距较大的图像。其函数也十分简单,只需要把阈值thresh设置为0,然后设置type为cv2.THRESH_BINARY+cv2.THRESH_OTSU,会自动返回一个合适的阈值。
ret2,th2 =cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

  • dst - 输出数组/图像(与src相同大小和类型以及相同通道数的数组/图像)

返回值:

  • retval - 阈值 thresh
  • dst - 经函数处理后的图像 image
    2.局部阈值法 : 当图像的色彩分布不均衡时,使用全局阈值处理的效果不是很好,这是使用局部阈值处理来进行分割,可以产生很好的效果。
    局部阈值的处理原理是,针对每一个像素点专门配置一个阈值来进行处理,这些阈值就构成了和原图像维度相同的矩阵。
    cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C, dst=None)
    参数:

  • src:原图像。必须是8位单通道的图像。

  • maxval:最大值。一般情况下为255
  • adaptiveMethod:自适应方法。高斯阈值算法:ADAPTIVE_THRESH_GAUSSIAN_C、平均阈值算法:ADAPTIVE_THRESH_MEAN_C
  • thresholdType:阈值处理方法。
  • blockSize:块的大小。必须为奇数3,5,7等等
  • c:常量。从平均值或加权平均值中减去的常数,可能为正数、0或者负数

灰度化图像

灰度图像上每个像素的颜色值又称为灰度,指黑白图像中点的颜色深度,范围一般从0到255,白色为255,黑色为0。所谓灰度值是指色彩的浓淡程度,灰度直方图是指一幅数字图像中,对应每一个灰度值统计出具有该灰度值的象素数。
图像灰度化处理有以下几种方式:

  1. 分量法:彩色图像中的三分量的亮度作为三个灰度图像的灰度值,可根据应用需要选取一种灰度图像
  2. 最大值法:将彩色图像中的三分量亮度的最大值作为灰度图的灰度值。
  3. 平均值法:将彩色图像中的三分量亮度求平均得到一个灰度值。
  4. 加权平均法:根据重要性及其它指标,将三个分量以不同的权值进行加权平均。由于人眼对绿色的敏感最高,对蓝色敏感最低,因此,按下式对RGB三分量进行加权平均能得到较合理的灰度图像。

灰度化函数:
cvtColor(src, code, dst=None, dstCn=None)->gray_image

参数:

  • src:源图像,这里指的是opencv摄像头读取到的RGB图像
  • code:因为这里是要将RGB图像转换为Gray图像,所有选择的方法是cv2.COLOR_RGB2GRAY
  • 其余为默认值即可。默认采取的灰度化方法是加权平均法

返回值:

  • gray_image:返回的是灰度化的图像。即三通道转换为单通道

源代码:

import cv2
import numpy as np
"""
二值化进行图像的背景分割:
1.全局阈值
2.局部阈值:表示自适应阈值算法,平均 (ADAPTIVE_THRESH_MEAN_C)或高斯(ADAPTIVE_THRESH_GAUSSIAN_C)
3.用户自己计算阈值:中值法计算阈值
4.HSV阈值的计算
"""

def nothing(*arg):
    pass


# 全局阈值
def threshold_demo(image, threshold_value):
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)  # 把输入图像灰度化
    # 直接阈值化(对输入的单通道矩阵逐像素进行阈值分割)表示的是二值化结合TRIANGLE法,全局自适应阈值,第二个参数值0可改为任意数字但不起作用,适用于单个波峰。
    ret, binary = cv2.threshold(gray, threshold_value, 255, cv2.THRESH_BINARY)
    print("threshold value %s" % ret)
    cv2.namedWindow("binary0", cv2.WINDOW_NORMAL)
    cv2.imshow("binary0", binary)


# 局部阈值:表示自适应阈值算法,平均 (ADAPTIVE_THRESH_MEAN_C)或高斯(ADAPTIVE_THRESH_GAUSSIAN_C)。
def local_threshold(image):
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)  # 把输入图像灰度化
    # 自适应阈值化能够根据图像不同区域亮度分布,改变阈值
    # 第三个参数必须为THRESH_BINARY或THRESH_BINARY_INV的阈值类型
    # 第四个参数blockSize参数表示块大小(奇数且大于1,比如3,5,7........ )。
    # 最后一个参数是常数,表示从平均值或加权平均值中减去的数
    # 补充:在使用平均和高斯两种算法情况下,通过计算每个像素周围blockSize x blockSize大小像素块的加权均值并减去常量C即可得到自适应阈值。如果使用平均的方法,则所有像素周围的权值相同;如果使用高斯的方法,则每个像素周围像素的权值则根据其到中心点的距离通过高斯方程得到。
    binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 25, 10)
    cv2.namedWindow("binary1", cv2.WINDOW_NORMAL)
    cv2.imshow("binary1", binary)


# 用户自己计算阈值:中值法计算阈值
def custom_threshold(image):
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)  # 把输入图像灰度化
    h, w = gray.shape[:2]
    m = np.reshape(gray, [1, w * h])
    mean = m.sum() / (w * h)
    print("mean:", mean)
    ret, binary = cv2.threshold(gray, mean, 255, cv2.THRESH_BINARY)
    cv2.namedWindow("binary2", cv2.WINDOW_NORMAL)
    cv2.imshow("binary2", binary)

# HSV阈值的调整,这里也可以通过HSV来对图像阈值进行调整
def HSV():
    cap = cv2.VideoCapture(0)
    # set blue thresh 设置HSV中蓝色、天蓝色范围
    lower_blue = np.array([78, 43, 46])
    upper_blue = np.array([110, 255, 255])

    while True:
        # get a frame and show 获取视频帧并转成HSV格式, 利用cvtColor()将BGR格式转成HSV格式,参数为cv2.COLOR_BGR2HSV。
        ret, frame = cap.read()
        cv2.imshow('Capture', frame)
        # change to hsv model
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

        # get mask 利用inRange()函数和HSV模型中蓝色范围的上下界获取mask,mask中原视频中的蓝色部分会被弄成白色,其他部分黑色。
        mask = cv2.inRange(hsv, lower_blue, upper_blue)
        cv2.imshow('Mask', mask)

        # detect blue 将mask于原视频帧进行按位与操作,则会把mask中的白色用真实的图像替换:
        res = cv2.bitwise_and(frame, frame, mask=mask)
        cv2.imshow('Result', res)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()


if __name__ == '__main__':
    cv2.namedWindow('colorThreshold')
    cv2.createTrackbar('threshold_value', 'colorThreshold', 0, 255, nothing)
    cap = cv2.VideoCapture(0)
    while True:
        ret, frame = cap.read()
        threshold_value = cv2.getTrackbarPos('threshold_value', 'colorThreshold')
        threshold_demo(frame, threshold_value)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()

效果:
调整的最终阈值:

分割出来的背景图片: