【第四章:OpenCv阈值分割/二值化(单通道、多通道图片)总结】

0.前言

  • 对一些算法的基本概念以及原理,本文不做过多的阐述,本文将一些相关基础知识以超链接的形式放在文章开头,大家根据需要进行挑选阅读,有基础的朋友可以直接跳过。

1.基础知识

1.1 什么是算子

  • 什么是算子: 高等数学上册P2中有这样的描述,算子即映射。可理解为从图像中的离散像素点集合通过某种关系,映射到另一个集合即可。

图1.1.1 算子即映射


1.2 图像处理中的图像分割技术

  • 对于图像处理中常见的分割,我这里做了个人的总结,同时,第三章主要以阈值分割为主,以及一些技巧的分享。在后面章节,会分享粘连物体的分割。

图1.2.1 图像处理中的分割

1.3 单通道图片的阈值分割

  • 注意:只要是单通道图片,就能进行二值化。 这里的单通道图片主要以Gray灰度图为主,但是在一些检测当中,需要用到其他色彩空间某些单通道的图片进行分割(因为某通道特征可能更为明显,更好分割)。后文会贴上程序,如何分离一张图片所有色彩空间下所有单通道图片。

  • 下面展示的是常用在单通道图片阈值分割的二值化算法
    在这里插入图片描述

图1.3.1 单通道图片二值化常用方法

1.4 推荐文章链接

1.多种色彩空间RGB、BGR、HSV /HSB、HSL、YUV的基本简介
2.多种边缘检测算法(Sobel算子、Isotropic Sobel算子、Roberts算子、Prewitt算子、Laplacian算子、Canny算子)介绍及比较
3.图像二值化方法汇总
4.图像二值化
5.多阈值 OTSU 处理方法
6.大津二值化
7.《opencv算法精解》全书笔记
8.opencv手册4.0中文文档



2. 灰度图分割

  • 个人比较常用的二值化算法是:简单二值化、大津二值化算法(图片亮度不均匀也能比较好分割)。其中简单二值化选取的阈值有时候可以借助灰度直方图,可以使阈值选取更为恰当,
  • 当图片有以下特点时可以考虑用灰度图分割: 检测物体对色彩特征没有要求,同时物体与背景像素值相差比较大。

2.1 灰度直方图

# 作者:OpenCv机器视觉
# 时间:2023/1/5
# 功能:灰度、BGR像素直方图
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt


# 绘制灰度直方图
def plot_demo(image):
    """
    画灰度图直方图:
    绘图都可以调用matplotlib.pyplot库来进行,其中的hist函数可以直接绘制直方图。
    plt.hist(arr, bins=50, normed=1, facecolor='green', alpha=0.75)
    hist的参数非常多,但常用的就这五个,只有第一个是必须的,后面四个可选
    arr: 需要计算直方图的一维数组
    bins: 直方图的柱数,可选项,默认为10
    normed: 是否将得到的直方图向量归一化。默认为0
    range参数表示箱子的下限和上限。即横坐标显示的范围,范围之外的将被舍弃
    """
    plt.hist(image.ravel(), 256, [0, 256],color="black")  # image.ravel()#ravel函数功能是将多维数组降为一维数组,统计各个bin的频次,256:bin的个数,[0, 256]:范围
    plt.show()  # 和OpenCV中的想要的直方图不同




def image_hist(image):
    """
    calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
    images参数表示输入图像,传入时应该用中括号[ ]括起来
    channels参数表示传入图像的通道,如果是灰度图像,那就不用说了,只有一个通道,值为0,
    如果是彩色图像(有3个通道),那么值为0,1,2,中选择一个,对应着BGR各个通道。这个值也得用[ ]传入。
    mask参数表示掩膜图像。如果统计整幅图,那么为None。
    主要是如果要统计部分图的直方图,就得构造相应的掩膜来计算。
    histSize参数表示灰度级的个数,需要中括号,比如[256]
    ranges参数表示像素值的范围,通常[0,256]。此外,假如channels为[0,1],ranges为[0,256,0,180],
    则代表0通道范围是0-256,1通道范围0-180。
    hist参数表示计算出来的直方图。
    """
    color = ('blue', 'green', 'red')  # 图像三通道
    for i, color in enumerate(color):
        hist = cv.calcHist([image], [i], None, [256], [0, 256])  # 绘制各个通道的直方图
        plt.plot(hist, color=color)  # 定义线的颜色
        plt.xlim([0, 256])  # x轴的范围
    plt.show()




src = cv.imread("img/1.png")
cv.namedWindow("input image",0)
cv.imshow("input image", src)

gray = cv.cvtColor(src,cv.COLOR_BGR2GRAY)
# 灰度直方图
plot_demo(gray)
# BGR像素直方图
image_hist(src)

cv.waitKey(0)
cv.destroyAllWindows()

  • 图片特征分析:不需要颜色特征,所以直接对其灰度图分割即可。根据灰度像素直方图可得我们得阈值设置在40-125左右即可。

    图2.1 灰度像素直方图


2.2 简单阈值分割与大津二值化分割

  • 代码,这里包含了简单阈值分割,自适应阈值分割、大津分割算法代码(代码涉及到python面向对象的知识点)。
# 作者:OpenCv机器视觉
# 时间:2023/1/5
# 功能:简单阈值分割,自适应阈值分割、大津分割算法代码
import cv2 as cv



class GetBinary(object):
    def __init__(self,img):
        self.img = img

    def threshed_fixed(self):
        """
        :function:利用固定阈值进行二值化
        :return:
        """

        blurred = cv.blur(self.img, (5,5))  # 这里进行5x5卷积核的均值滤波处理
        gray = cv.cvtColor(blurred,cv.COLOR_BGR2GRAY)

        ret,bin = cv.threshold(gray,100,255,cv.THRESH_BINARY)
        return bin
    def adaptive_threshold(self):
        """
        :function:利用自适应局部二值化方法进行二值化
        :return:
        """
        blurred = cv.blur(self.img, (5,5))  # 这里进行5x5卷积核的均值滤波处理
        gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
        bin = cv.adaptiveThreshold(src=gray,maxValue=255,adaptiveMethod=cv.ADAPTIVE_THRESH_MEAN_C,thresholdType=cv.THRESH_BINARY,blockSize=31,C=1)
        return bin


    def threshed_otsus(self):
        """
        :function:利用OTSU's二值化算法阈值进行二值化
        :return:
        """
        blurred = cv.blur(self.img, (5, 5))  # 这里进行5x5卷积核的均值滤波处理
        gray = cv.cvtColor(blurred,cv.COLOR_BGR2GRAY)
        ret,bin=  cv.threshold(gray,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
        return bin


img = cv.imread(".\\img\\1.png")
# 定义一个对象
get_binary = GetBinary(img)
# 调用对象中的方法
bin1 = get_binary.threshed_fixed()      # 简单阈值分割
bin2 = get_binary.adaptive_threshold()  # 自适应阈值分割
bin3 = get_binary.threshed_otsus()      # 大津算法分割




cv.namedWindow("img",0)
cv.imshow("img",img)

cv.namedWindow("threshed_fixed",0)
cv.imshow("threshed_fixed",bin1)
cv.namedWindow("adaptive_threshold",0)
cv.imshow("adaptive_threshold",bin2)
cv.namedWindow("threshed_otsus",0)
cv.imshow("threshed_otsus",bin3)


cv.waitKey(0)
cv.destroyAllWindows()

图2.2 简单阈值分割与大津二值化分割分割效果

  • 参考链接

1.灰度直方图、BGR像素直方图

2.matplotlib画图基本操作



3.分离常见色彩空间下的单通道图片

  • 背景意义:当彩色图片下的目标与背景区分度不是很高,这时候我们可以考虑分离各通道下的图片,观察在哪个通道下的特征比较明显,便于后期的阈值分割。这里举例子的是某课题细胞分割图片。

图3.1 某细胞图片


  • 代码
# 作者:OpenCv机器视觉
# 时间:2023/1/6
# 功能:获取HSV 、LAB、HIS、LUV、YUV色彩空间下各单通道图片
import cv2 as cv
import os




def split_all_chancel(img):

    # 色彩空间转换
    gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    HSV = cv.cvtColor(img, cv.COLOR_BGR2HSV)
    LAB = cv.cvtColor(img, cv.COLOR_BGR2LAB)
    HIS = cv.cvtColor(img, cv.COLOR_BGR2HLS)
    LUV = cv.cvtColor(img, cv.COLOR_BGR2LUV)
    YUV = cv.cvtColor(img, cv.COLOR_BGR2YCrCb)

    # 对各图片通道进行拆分
    bgr_b, bgr_g, bgr_r = cv.split(img)
    hsv_h, hsv_s, hsv_v = cv.split(HSV)
    lab_l, lab_a, lab_b = cv.split(LAB)
    his_h, his_i, his_s = cv.split(HIS)
    luv_l, luv_u, luv_v = cv.split(LUV)
    yuv_y, yuv_u, yuv_v = cv.split(YUV)
    return  ([hsv_h, hsv_s, hsv_v,lab_l, lab_a, lab_b,  his_h, his_i, his_s,luv_l, luv_u, luv_v,yuv_y, yuv_u, yuv_v,bgr_b, bgr_g, bgr_r,gray],
            ["hsv_h"," hsv_s", "hsv_v","lab_l", "lab_a", "lab_b",  "his_h", "his_i", "his_s","luv_l", "luv_u", "luv_v","yuv_y", "yuv_u", "yuv_v","bgr_b","bgr_g","bgr_r","gray"])


# 原图片路径
img_path = ".\\img\\2.jpg"

img = cv.imread(img_path)                       # 读取图片
name = os.path.splitext(img_path)[0]            # 图片文件名
extend_name = os.path.splitext(img_path)[-1]    # 图片扩展名
if not os.path.exists(name):                    # 判断以图片名 为命名的文件夹是否存在
    os.makedirs(name)                           # 不存在就创建文件夹,用于存放图片

# 调用分离通道函数
channels_imgs,channel_str = split_all_chancel(img)
for i, channels_img in enumerate(channels_imgs):
    out_name = os.path.join(name,channel_str[i]+".png")   # 保存路径,为图片相同路径下
    print(out_name)
    cv.imwrite(out_name, channels_img)



  • 通道分离效果如下,从分离的单通道图片中,不难看出,HSV色彩空间下的V通道特征比较明显(BGR_G,LAB_L通道也比较明显,都可以采用此通道进行阈值分割,但是常用的还是HSV色彩空间),因此下文通过HSV色彩空间转换,对细胞进行分割识别。

图3.2  常见色彩空间下的单通道图

4. HSV分割

4.1 常见分割代码

  • HSV的上下阈值根据 HSV颜色分量范围表 来确定

图4.1.1 HSV颜色分量范围表

  • 因为细胞是偏绿色,所以这里根据颜色分量范围表进行设置高低阈值
lower = np.array([35, 43, 46])
upper = np.array([77, 255, 255])
  • 代码:
# 作者:OpenCv机器视觉
# 时间:2023/1/6
# 功能:根据HSV颜色分量表进行阈值分割识别

import cv2 as cv
import numpy as np


path = ".\\img\\2.jpg"      # 图片位置
img = cv.imread(path)                                   #读取图像
imgHsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)              #转换为HSV色彩空间
lower = np.array([35, 43, 46])                          #定义低阈值
upper = np.array([77, 255, 255])                        #定义高阈值
mask = cv.inRange(imgHsv,lower,upper)                   #获取分割掩膜图
imgResult = cv.bitwise_and(img,img,mask,mask=mask)       # 将掩膜图与原图进行运算,白色区域目标显示为彩色效果



contours = cv.findContours(mask.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[0]  # 获取图片的轮廓
for c in contours:                    # 获取每个轮廓
        x, y, w, h = cv.boundingRect(c)
        cv.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2 )  # 画外接矩形


cv.namedWindow("mask",0)
cv.imshow("mask",mask)
cv.namedWindow("img", 0)
cv.imshow("img", img)
cv.namedWindow("imghsv",0)
cv.imshow("imghsv", imgHsv)

cv.waitKey(0)

  • 分割效果:对颜色较为明显的细胞能识别到,但是对于染色不为明显的细胞,漏识别。难道阈值我们就要根据这个表去一个个尝试吗?这样效率太低了,下面会介绍一款非常好用的滑动条工具。

图4.1.2 通过HSV颜色分量表定义阈值范围 识别效果


4.2 技巧1,通过鼠标感应,获取某个像素的的HSV像素值

  • 该操作主要了解以下鼠标感应,获取图像某位置的信息。要更好地进行目标识别,还是需要利用技巧2中的滑动条。
# 作者:OpenCv机器视觉
# 时间:2023/1/6
# 功能:通过鼠标感应,点击鼠标左键,获取该坐标的相关信息,可以是BGR值,可以是坐标,也可以是灰度值,这里是以HSV值为例,大家可以根据想法更改程序

import cv2 as cv

# 图片路径
img = cv.imread("img\\2.jpg")

def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
    if event == cv.EVENT_LBUTTONDOWN:
        hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)  # 图片重新加载,用于刷新,保证上一步的显示内容不被显示
        xy = "%d,%d" % (x, y)
        print("坐标:",(x,y),"HSV值",hsv[y][x]) # hsv[y][x]因为图片第一个参数是高,第二个参数是宽
        cv.putText(hsv, xy, (x, y), cv.FONT_HERSHEY_PLAIN,2, (0, 0, 255), thickness=2)
        cv.imshow("HSV", hsv)


hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)     # 色彩空间转换
cv.namedWindow("HSV",0)
cv.setMouseCallback("HSV", on_EVENT_LBUTTONDOWN)
cv.imshow("HSV", hsv)

cv.waitKey(0)

图4.2 鼠标感应获取图片像素点信息


4.2 最佳技巧性工具:借助滑动条,快速实现基于颜色的目标识别

  • 代码
# 作者:OpenCv机器视觉
# 时间:2023/1/6
# 功能:借助滑动条进行颜色识别
import cv2 as cv
import numpy as np



path = ".\\img\\2.jpg"      # 图片位置

def empty():
    pass


cv.namedWindow("TrackBars",0)
cv.createTrackbar("Hue Min","TrackBars",0,179,empty)
cv.createTrackbar("Hue Max","TrackBars",179,179,empty)
cv.createTrackbar("Sat Min","TrackBars",0,255,empty)
cv.createTrackbar("Sat Max","TrackBars",255,255,empty)
cv.createTrackbar("Val Min","TrackBars",0,255,empty)
cv.createTrackbar("Val Max","TrackBars",255,255,empty)


while True:

    # 获取滑动条参数值
    h_min = cv.getTrackbarPos("Hue Min","TrackBars")
    h_max = cv.getTrackbarPos("Hue Max", "TrackBars")
    s_min = cv.getTrackbarPos("Sat Min", "TrackBars")
    s_max = cv.getTrackbarPos("Sat Max", "TrackBars")
    v_min = cv.getTrackbarPos("Val Min", "TrackBars")
    v_max = cv.getTrackbarPos("Val Max", "TrackBars")



    img = cv.imread(path)                                   #读取图像
    print("lower = np.array("+str([h_min,s_min,v_min])+")")
    print("upper = np.array("+str([h_max,s_max,v_max])+")")
    imgHsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)              #转换为HSV色彩空间
    lower = np.array([h_min,s_min,v_min])                    #定义低阈值
    upper = np.array([h_max,s_max,v_max])                    #定义高阈值
    mask = cv.inRange(imgHsv,lower,upper)                   #获取灰度图
    imgResult = cv.bitwise_and(img,img,mask,mask=mask)       #目标显示RGB



    # 对识别后的图像进行框选
    area = []  # 定义一个列表来图片的面积
    contours = cv.findContours(mask.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[0]  # 获取图片的轮廓 ,不同python有的索引值是0,有的是1
    if  h_min>0  or v_min>0 or s_min>0 or h_max<180 or s_max<255 or v_max<255:       # 当检测到有拖动的时候再开始轮廓的面积计算,因为有的图片初始化没有发现轮廓,计算面积就会报错,
        for c in contours:                    # 获取每个轮廓
            if cv.contourArea(c)>10:    # 进行滤波,将一些太小的噪点过滤掉
                x, y, w, h = cv.boundingRect(c)
                cv.rectangle(img, (x, y), (x + w, y + h), (0, 255, 255), 2 )  # 画外接矩形






    cv.namedWindow("mask",cv.WINDOW_NORMAL)
    cv.imshow("mask",mask)
    cv.namedWindow("img", cv.WINDOW_NORMAL)
    cv.imshow("img", img)

    cv.waitKey(1)

  • 识别效果

视频4.2 滑动条识别效果


5 总结

  • 本章节主要内容为阈值分割
    1)提到了图像分割方法;
    2)常用的二值化方法、如何根据需求进行通道分类,进行阈值分割
    3)推荐了颜色识别当中最好用的滑动条工具。
    4)以及个人整理的源代码

  • 本文没有详细介绍原理,多为个人学习总结,底层原理内容多以超链接形式供大家选择阅读。因个人总结可能有点漏缺,如有错误地方欢迎大家批评指正。原创不易,如果大家觉得文章不错,欢迎点赞收藏!!!

6. 其他章节链接


1.理论系列:

第一章:pycharm、anaconda、opencv、pytorch、tensorflow、paddlex等环境配置大全总结【图像处理py版本】

第二章:OpenCv算法的基本介绍与应用

第三章:OpenCv图片、视频读写操作与基本应用

==》第四章:OpenCv阈值分割/二值化(单通道、多通道图片)总结


2.项目系列:

项目一:四六级改卷系统
项目二:实战篇:粘连物体分割——利用几何分割实现瓶盖分割检测
项目三:实战篇:粘连物体分割——利用几何分割实现硬币分割检测
项目四:实战篇:粘连物体分割——利用几何分割实现细胞分割检测
项目五:实战篇:粘连物体分割——利用分水岭算法实现糖豆分割检测

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
OpenCV中,图像阈值二值化是一种基本的图像处理操作,可以将图像转换为二值图像。OpenCV提供了两种常用的图像阈值二值化方法:全局阈值二值化和自适应阈值二值化。全局阈值二值化是指将整个图像分割为黑白两个部分,而自适应阈值二值化是指根据图像的局部区域来确定阈值,从而得到更精确的二值化结果。 在OpenCV中,全局阈值二值化操作的C API如下: double cv::threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type) 其中,src表示输入图像,dst表示输出的二值化图像,thresh表示设定的阈值,maxval表示阈值以上的像素值,type表示二值化的类型。 另外,OpenCV还提供了一些其他的阈值操作方法。自适应阈值二值化是其中之一,其API如下: void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C) 其中,src表示输入图像,dst表示输出的二值化图像,maxValue表示阈值以上的像素值,adaptiveMethod表示自适应阈值的计算方法,thresholdType表示二值化的类型,blockSize表示局部阈值计算的邻域大小,C表示从计算得到的阈值中减去的常数。 总结起来,OpenCV提供了多种图像阈值二值化方法,可以根据具体需求选择合适的方法进行二值化操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [二值图像分析:OpenCV中的二值化阈值操作](https://blog.csdn.net/PecoHe/article/details/113876296)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [【OpenCv】阈值操作(超详细)](https://blog.csdn.net/qq_49838656/article/details/119516784)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值