您好,
会员登录 快速注册
退出 ( 条未读消息)
关于本站 意见反馈 首页

公告:小宅博客网可以开发票了,需要发票的,去群里找群主哈!!
全部文章分类
  • 人工智能 >

  • 编程语言 >

  • WPF系列 >

  • ASP.NET系列 >

  • Linux >

  • 数据库 >

  • 嵌入式 >

  • WEB技术 >

  • PLC系列 >

  • 微服务与框架 >

  • 小宅DIY >

  • 学习资料 >

OpenCv基础 ANN车牌识别 yolov5车牌识别 指针式仪表识别 ROS系列 YOLO Halcon Detectron2 昇腾AI ChatGPT在线体验 英伟达JETSON ChatGLM ChatTTS FunASR 地平线 ByteTrack 魔搭社区 LangChain
C C# C++ Python Java Go
WPF
ASP.NET小功能 GPS定位系统-MVC GPS定位系统-VUE ASP.NET WebRTC
Linux Linux内核 Shell MakeFile
MySql SqlServer Oracle
STM8 STM32 51单片机
VUE入门 HTML JavaScript CSS layui镜像网站 ElementUi中文官网 element-plus 图标
三菱 欧姆龙 西门子 施耐德 松下 台达
IOTSharp IOTGateway ABP FRAMEWORK Docker
亚克力音响 编程仙途:智驭万法
面试题与技巧 Python入门技能树 微软C#教程
首页 编程之美 工具下载 全国就业 流量地图 文心一言
OpenCv基础
内容介绍与资料分享 C# OpenCv环境搭建 C++ OpenCv环境搭建 Python OpenCv环境搭建 Java OpenCv环境搭建 OpenCv组件结构解析 OpenCv命名规范 OpenCv基本专业术语与方法 OpenCV 常用函数与构造体详细说明 创建画布 打开一张图片 利用imwrite生成透明png图像 图像打开、混合显示和输出 图像腐蚀 blur图像模糊(均值滤波) sobel边缘检测 canny边缘检测 Scharr滤波器 程序性能检测及优化 视频播放 摄像头录像与播放 双摄像头操作与图像相似度检测 颜色空间转换与物体追踪 彩色目标追踪 光流法运动目标检测 OpenCV中的稠密光流 背景减除 点追踪 人脸识别 支持向量机之SVM引导 支持向量机之处理线性不可分数据 ROI矩形截取 鼠标绘制矩形 用OpenCV进行基本绘图 绘图函数(python中文显示) 把鼠标当画笔 用滑动条做调色板 图像的基础操作 图像上的算术运算 多通道图像混合 图像的亮度、对比度调整 XML和YAML文件的写入 XML和YAML文件的读取 卷积操作 三种线性滤波 两种非线性滤波 7种图像处理形态学(1) 7种图像处理形态学(2) 漫水填充 图像缩放与图像金字塔 二值化基本阈值操作 图像阈值 Laplacian图像变换(拉普拉斯算子) 霍夫变换HoughLines边缘检测与线性矢量 霍夫变换HoughLinesP边缘检测与线性矢量 霍夫变换HoughCircles边缘检测与线性矢量 LSD快速直线检测 几何变换 remap重映射 remap实现多种重映射 仿射变换综合示例 直方图均衡化 CLAHE有限对比适应性直方图均衡化 draw最大的轮廓 轮廓的性质 点到多边形的最短距离 形状匹配 椭圆拟合与直线拟合 基础轮廓查找 查找并绘制轮廓综合示例 凸缺陷/凸包检测 凸包检测 创建包围轮廓的矩形边界 创建包围轮廓的圆形边 创建包围轮廓的矩形和圆形边界框 查找和绘制图片轮廓矩 分水岭算法 图像修补 H-S二维直方图的绘制/2D直方图 一维直方图的绘制 RGB三色直方图的绘制 直方图对比 使用掩膜绘制直方图 直方图反向投影 模板匹配 多对象模板匹配 cornerHarris角点检测 cornerHarris角点检测综合示例 Shi-Tomasi角点检测 亚像素级角点检测 角点检测的FAST算法(FAST特征检测器) 颜色识别 warpPerspective透视变换 SURF/SIFT特征点检测 SURF/SIFT特征描述 使用FLANN进行特征点匹配 FLANN结合SURF/SIFT进行关键点的描述和匹配 寻找已知物体(一) 寻找已知物体(二) 目标查找与跟踪 - Meanshift与CamShift BRIEF描述符 ORB ORB算法描述与匹配 LUT 图像灰度调整 离散傅里叶变换 双目摄像头与图像拼接 环境亮度检测 stitching 全景拼接 Maze-Solver迷宫解密 使用Haar分类器之面部检测 使用Haar分类器之行人检测 OpenCv Haar/LBP/HOG分类器-人脸识别 斑点检测 使用GrabCut算法进行交互式前景提取 对极几何 摄像机标定 姿势估计 立体图像中的深度地图 OpenCv中的KNN KNN手写数字识别 ​SVM手写数字识别(使用SVM进行手写数据OCR) 英文字母的OCR 预测手写数字(预测不准) K值聚类(一) K值聚类(二) 计算摄影学-图像去噪 高动态范围成像(HDRI或HDR) MSER区域检测 二维码、条形码识别 删除图像中的水印 OpenCv深度学习dnn Kinect-深度相机 OpenCv常用数学算法 360度旋转直线绘制 向量延长线上的像素扫描 Tools工具包-窗体分配
二值化基本阈值操作
Laplacian图像变换(拉普拉斯算子)
激萌の小宅 小宅博客网 OpenCv基础

文章作者:激萌の小宅

促销:¥0

价格:¥0

配送方式: 购买后立即生效(如购买异常,请联系站长)
付款之后一定要等待自动跳转结束,否则购买可能会失败
  • 0 天

    有效期

  • 0

    总销量

  • 0

    累计评价

图像阈值

本章节内容是博主网上收集的。当前系列所有demo下载地址:

https://github.com/GaoRenBao/OpenCv4-Demo

不同编程语言对应的OpenCv版本以及开发环境信息如下: 

语言

OpenCv版本

IDE

C#

OpenCvSharp4.4.8.0.20230708

Visual Studio 2022

C++

OpenCv-4.5.5-vc14_vc15

Visual Studio 2022

Python

OpenCv-Python (4.6.0.66)

PyCharm Community Edition 2022.1.3


C#版本运行效果及代码如下:

【请参考其他文章中的使用方法】


C++版本运行效果及代码如下:

【请参考其他文章中的使用方法】


Python版本运行效果及代码如下:

python版本代码一共有4套,主要包括:

简单阈值demo1.py:全局简单阈值

        与名字一样,这种方法非常简单。但像素值高于阈值时,我们给这个像素赋予一个新值(可能是白色),否则我们给它赋予另外一种颜色(也许是黑色)。这个函数就是cv2.threshhold()。这个函数的第一个参数就是原图像,原图像应该是灰度图。第二个参数就是用来对像素值进行分类的阈值。第三个参数就是当像素值高于(有时是小于)阈值时应该被赋予的新的像素值。

    OpenCV 提供了多种不同的阈值方法 , 是由第四个参数来决定的。

    这些方法包括

    • cv2.THRESH_BINARY

    • cv2.THRESH_BINARY_INV 

    • cv2.THRESH_TRUNC

    • cv2.THRESH_TOZERO

    • cv2.THRESH_TOZERO_INV


demo2.py:自适应阈值

       在前面的部分我们使用是全局间值,整幅图像采用同一个数作为间值。当时这种方法并不适应与所有情况,尤其是当同一幅图像上的不同部分的具有不同亮度时。这种情况下我们需要采用自适应间值。此时的间值是根据图像上的每一个小区域计算与其对应的阀值。因此在同一幅图像上的不同区域采用的是不同的间值,从而使我们能在亮度不同的情况下得到更好的结果。

这种方法需要我们指定三个参数,返回值只有一个。

AdaptiveMethod 指定计算间值的方法。

    • cv2.ADPTIVE_THRESHMEANC:值取自相邻区域的平均值

    • CV2.ADPTIVE_THRESHGAUSSIANC:闵值取值相邻区域的加权和,权重为一个高斯窗口

    • Block Size 邻域大小(用来计算阀值的区域大小)

    • C 这就是是一个常数,间值就等于的平均值或者加权平均值减去这个常数。


demo3.py:

        在第一部分中我们提到过retVal,当我们使用Otsu二值化时会用到它那么它到底是什么呢?

        在使用全局阁值时,我们就是随便给了一个数来做阁值,那我们怎么知道我们选取的这个数的好坏呢?答案就是不停的尝试。如果是一副双峰图像(简单来说双峰图像是指图像直方图中存在两个峰)呢?我们巨不是应该在两个峰之间的峰谷选一个值作为闹值?这就是Otsu二值化要做的。简单来说就是对一副双峰图像自动根据其直方图计算出一个阁值。(对于非双峰图像,这种方法得到的结果可能会不理想)。

        这里用到到的函数还是cv2.threshold(),但是需要多传入一个参数(flag):cv2.THRESH_OTSU。这时要把阀值设为0。然后算法会找到最优商值,这个最优闹值就是返回值retVal。如果不使用Otsu二值化,返回的retVal值与设定的间值相等。

        下面的例子中,输入图像是一副带有噪声的图像。第一种方法,我们设127为全局阀值。第二种方法,我们直接使用Otsu二值化。第三种方法,我们首先使用一个5x5的高斯核除去噪音,然后再使用Otsu二值化。看看噪音去除对结果的影响有多大吧。


demo4.py:

        在这一部分我们会演示怎样使用Python来实现Otsu二值化算法,从而告诉大家它是如何工作的。如果你不感兴趣的话可以跳过这一节。

        因为是双峰图,Otsu算法就是要找到一个阀值(t),使得同一类加权方差最小,需要满足下列关系式:(其实我也看不懂这啥东西。。。)

QQ截图20220907221432.jpg

        其实就是在两个峰之间找到一个阀值t,将这两个峰分开,并且使每一个峰内的方差最小。


简单阈值demo1.py,演示效果和代码如下:

演示原图:

grey-gradient.jpg

演示效果:

QQ截图20220907213153.jpg

源码如下:

import cv2
from matplotlib import pyplot as plt

img = cv2.imread('../images/7067.jpg', 0)

ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)

titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

for i in range(6):
    plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()


demo2.py:自适应阈值,演示效果和代码如下

测试原图如下:

sudoku.jpg

测试效果如下:

QQ截图20220907212248.jpg

'''
自适应阈值

Adaptive Method- 指定 算阈值的方法。
– cv2.ADPTIVE_THRESH_MEAN_C  值取自相邻区域的平均值
– cv2.ADPTIVE_THRESH_GAUSSIAN_C  值取值相邻区域 的加权和 ,权重为一个高斯窗口
'''

import cv2
from matplotlib import pyplot as plt

img = cv2.imread('../images/sudoku.jpg', 0)
# 中值滤波
img = cv2.medianBlur(img, 5)
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

# 11 为 Block size 邻域大小 用来计算阈值的区域大小 ,
# 2 为 C值,常数, 阈值就等于的平均值或者加权平均值减去这个常数。
th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
th3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)

titles = ['Original Image', 'Global Thresholding (v = 127)',
          'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]

for i in range(4):
    plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])

plt.show()


demo3.py:演示效果和代码如下

测试原图如下:

noisy2.png

测试效果如下:

QQ截图20220907220827.jpg

import cv2
from matplotlib import pyplot as plt

img = cv2.imread('../images/noisy2.png', 0)
# global thresholding
ret1, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# Otsu's thresholding
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# Otsu's thresholding after Gaussian filtering
# 5,5 为 斯核的大小 0 为标准差
blur = cv2.GaussianBlur(img, (5, 5), 0)
# 阀值一定为 0
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# plot all the images and their histograms
images = [img, 0, th1,
          img, 0, th2,
          blur, 0, th3]
titles = ['Original Noisy Image', 'Histogram', 'Global Thresholding (v=127)',
          'Original Noisy Image', 'Histogram', "Otsu's Thresholding",
          'Gaussian filtered Image', 'Histogram', "Otsu's Thresholding"]
# 使用了 pyplot 中画直方图的方法 plt.hist,
# 注意的是它的参数是一维数组
# 所以使用了 numpy ravel 方法 将多维数组 换成一维 也可以使用 flatten 方法
# ndarray.flat 1-D iterator over an array.
# ndarray.flatten 1-D array copy of the elements of an array in row-major order.

for i in range(3):
    plt.subplot(3, 3, i * 3 + 1), plt.imshow(images[i * 3], 'gray')
    plt.title(titles[i * 3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3, 3, i * 3 + 2), plt.hist(images[i * 3].ravel(), 256)
    plt.title(titles[i * 3 + 1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3, 3, i * 3 + 3), plt.imshow(images[i * 3 + 2], 'gray')
    plt.title(titles[i * 3 + 2]), plt.xticks([]), plt.yticks([])
plt.show()


demo4.py:演示效果和代码如下

测试图像为前面的“noisy2.png”

运行结果如下:

QQ截图20231107113924.jpg

代码如下:

import cv2
import numpy as np

img = cv2.imread('../images/noisy2.png', 0)
blur = cv2.GaussianBlur(img, (5, 5), 0)
# find normalized_histogram, and its cumulative distribution function
#  算归一化直方图
# CalcHist(image, accumulate=0, mask=NULL)

hist = cv2.calcHist([blur], [0], None, [256], [0, 256])
hist_norm = hist.ravel() / hist.max()
Q = hist_norm.cumsum()

bins = np.arange(256)
fn_min = np.inf
thresh = -1

for i in range(1, 256):
    p1, p2 = np.hsplit(hist_norm, [i])  # probabilities
    q1, q2 = Q[i], Q[255] - Q[i]  # cum sum of classes
    b1, b2 = np.hsplit(bins, [i])  # weights

    # finding means and variances
    m1, m2 = np.sum(p1 * b1) / q1, np.sum(p2 * b2) / q2
    v1, v2 = np.sum(((b1 - m1) ** 2) * p1) / q1, np.sum(((b2 - m2) ** 2) * p2) / q2

    # calculates the minimization function
    fn = v1 * q1 + v2 * q2
    if fn < fn_min:
        fn_min = fn
        thresh = i

# find otsu's threshold value with OpenCV function
ret, otsu = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

print(thresh, ret)


二值化基本阈值操作
Laplacian图像变换(拉普拉斯算子)

友情链接: CSDN激萌の小宅 95知识库 自考题库 罗分明个人网络博客 精益编程leanboot

小宅博客  www.bilibili996.com All Rights Reserved. 备案号: 闽ICP备2024034575号

网站经营许可证  福建省福州市 Copyright©2021-2025 版权所有

小宅博客
首页 智能家居 地图定位
公告:小宅博客网可以开发票了,需要发票的,去群里找群主哈!!

文章作者:激萌の小宅

促销:¥0

价格:¥0

配送方式: 购买后立即生效(如购买异常,请联系站长)
付款之后一定要等待自动跳转结束,否则购买可能会失败
  • 0 天

    有效期

  • 0

    总销量

  • 0

    累计评价

图像阈值

本章节内容是博主网上收集的。当前系列所有demo下载地址:

https://github.com/GaoRenBao/OpenCv4-Demo

不同编程语言对应的OpenCv版本以及开发环境信息如下: 

语言

OpenCv版本

IDE

C#

OpenCvSharp4.4.8.0.20230708

Visual Studio 2022

C++

OpenCv-4.5.5-vc14_vc15

Visual Studio 2022

Python

OpenCv-Python (4.6.0.66)

PyCharm Community Edition 2022.1.3


C#版本运行效果及代码如下:

【请参考其他文章中的使用方法】


C++版本运行效果及代码如下:

【请参考其他文章中的使用方法】


Python版本运行效果及代码如下:

python版本代码一共有4套,主要包括:

简单阈值demo1.py:全局简单阈值

        与名字一样,这种方法非常简单。但像素值高于阈值时,我们给这个像素赋予一个新值(可能是白色),否则我们给它赋予另外一种颜色(也许是黑色)。这个函数就是cv2.threshhold()。这个函数的第一个参数就是原图像,原图像应该是灰度图。第二个参数就是用来对像素值进行分类的阈值。第三个参数就是当像素值高于(有时是小于)阈值时应该被赋予的新的像素值。

    OpenCV 提供了多种不同的阈值方法 , 是由第四个参数来决定的。

    这些方法包括

    • cv2.THRESH_BINARY

    • cv2.THRESH_BINARY_INV 

    • cv2.THRESH_TRUNC

    • cv2.THRESH_TOZERO

    • cv2.THRESH_TOZERO_INV


demo2.py:自适应阈值

       在前面的部分我们使用是全局间值,整幅图像采用同一个数作为间值。当时这种方法并不适应与所有情况,尤其是当同一幅图像上的不同部分的具有不同亮度时。这种情况下我们需要采用自适应间值。此时的间值是根据图像上的每一个小区域计算与其对应的阀值。因此在同一幅图像上的不同区域采用的是不同的间值,从而使我们能在亮度不同的情况下得到更好的结果。

这种方法需要我们指定三个参数,返回值只有一个。

AdaptiveMethod 指定计算间值的方法。

    • cv2.ADPTIVE_THRESHMEANC:值取自相邻区域的平均值

    • CV2.ADPTIVE_THRESHGAUSSIANC:闵值取值相邻区域的加权和,权重为一个高斯窗口

    • Block Size 邻域大小(用来计算阀值的区域大小)

    • C 这就是是一个常数,间值就等于的平均值或者加权平均值减去这个常数。


demo3.py:

        在第一部分中我们提到过retVal,当我们使用Otsu二值化时会用到它那么它到底是什么呢?

        在使用全局阁值时,我们就是随便给了一个数来做阁值,那我们怎么知道我们选取的这个数的好坏呢?答案就是不停的尝试。如果是一副双峰图像(简单来说双峰图像是指图像直方图中存在两个峰)呢?我们巨不是应该在两个峰之间的峰谷选一个值作为闹值?这就是Otsu二值化要做的。简单来说就是对一副双峰图像自动根据其直方图计算出一个阁值。(对于非双峰图像,这种方法得到的结果可能会不理想)。

        这里用到到的函数还是cv2.threshold(),但是需要多传入一个参数(flag):cv2.THRESH_OTSU。这时要把阀值设为0。然后算法会找到最优商值,这个最优闹值就是返回值retVal。如果不使用Otsu二值化,返回的retVal值与设定的间值相等。

        下面的例子中,输入图像是一副带有噪声的图像。第一种方法,我们设127为全局阀值。第二种方法,我们直接使用Otsu二值化。第三种方法,我们首先使用一个5x5的高斯核除去噪音,然后再使用Otsu二值化。看看噪音去除对结果的影响有多大吧。


demo4.py:

        在这一部分我们会演示怎样使用Python来实现Otsu二值化算法,从而告诉大家它是如何工作的。如果你不感兴趣的话可以跳过这一节。

        因为是双峰图,Otsu算法就是要找到一个阀值(t),使得同一类加权方差最小,需要满足下列关系式:(其实我也看不懂这啥东西。。。)

QQ截图20220907221432.jpg

        其实就是在两个峰之间找到一个阀值t,将这两个峰分开,并且使每一个峰内的方差最小。


简单阈值demo1.py,演示效果和代码如下:

演示原图:

grey-gradient.jpg

演示效果:

QQ截图20220907213153.jpg

源码如下:

import cv2
from matplotlib import pyplot as plt

img = cv2.imread('../images/7067.jpg', 0)

ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV)

titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

for i in range(6):
    plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()


demo2.py:自适应阈值,演示效果和代码如下

测试原图如下:

sudoku.jpg

测试效果如下:

QQ截图20220907212248.jpg

'''
自适应阈值

Adaptive Method- 指定 算阈值的方法。
– cv2.ADPTIVE_THRESH_MEAN_C  值取自相邻区域的平均值
– cv2.ADPTIVE_THRESH_GAUSSIAN_C  值取值相邻区域 的加权和 ,权重为一个高斯窗口
'''

import cv2
from matplotlib import pyplot as plt

img = cv2.imread('../images/sudoku.jpg', 0)
# 中值滤波
img = cv2.medianBlur(img, 5)
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

# 11 为 Block size 邻域大小 用来计算阈值的区域大小 ,
# 2 为 C值,常数, 阈值就等于的平均值或者加权平均值减去这个常数。
th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
th3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)

titles = ['Original Image', 'Global Thresholding (v = 127)',
          'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]

for i in range(4):
    plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])

plt.show()


demo3.py:演示效果和代码如下

测试原图如下:

noisy2.png

测试效果如下:

QQ截图20220907220827.jpg

import cv2
from matplotlib import pyplot as plt

img = cv2.imread('../images/noisy2.png', 0)
# global thresholding
ret1, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# Otsu's thresholding
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# Otsu's thresholding after Gaussian filtering
# 5,5 为 斯核的大小 0 为标准差
blur = cv2.GaussianBlur(img, (5, 5), 0)
# 阀值一定为 0
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# plot all the images and their histograms
images = [img, 0, th1,
          img, 0, th2,
          blur, 0, th3]
titles = ['Original Noisy Image', 'Histogram', 'Global Thresholding (v=127)',
          'Original Noisy Image', 'Histogram', "Otsu's Thresholding",
          'Gaussian filtered Image', 'Histogram', "Otsu's Thresholding"]
# 使用了 pyplot 中画直方图的方法 plt.hist,
# 注意的是它的参数是一维数组
# 所以使用了 numpy ravel 方法 将多维数组 换成一维 也可以使用 flatten 方法
# ndarray.flat 1-D iterator over an array.
# ndarray.flatten 1-D array copy of the elements of an array in row-major order.

for i in range(3):
    plt.subplot(3, 3, i * 3 + 1), plt.imshow(images[i * 3], 'gray')
    plt.title(titles[i * 3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3, 3, i * 3 + 2), plt.hist(images[i * 3].ravel(), 256)
    plt.title(titles[i * 3 + 1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3, 3, i * 3 + 3), plt.imshow(images[i * 3 + 2], 'gray')
    plt.title(titles[i * 3 + 2]), plt.xticks([]), plt.yticks([])
plt.show()


demo4.py:演示效果和代码如下

测试图像为前面的“noisy2.png”

运行结果如下:

QQ截图20231107113924.jpg

代码如下:

import cv2
import numpy as np

img = cv2.imread('../images/noisy2.png', 0)
blur = cv2.GaussianBlur(img, (5, 5), 0)
# find normalized_histogram, and its cumulative distribution function
#  算归一化直方图
# CalcHist(image, accumulate=0, mask=NULL)

hist = cv2.calcHist([blur], [0], None, [256], [0, 256])
hist_norm = hist.ravel() / hist.max()
Q = hist_norm.cumsum()

bins = np.arange(256)
fn_min = np.inf
thresh = -1

for i in range(1, 256):
    p1, p2 = np.hsplit(hist_norm, [i])  # probabilities
    q1, q2 = Q[i], Q[255] - Q[i]  # cum sum of classes
    b1, b2 = np.hsplit(bins, [i])  # weights

    # finding means and variances
    m1, m2 = np.sum(p1 * b1) / q1, np.sum(p2 * b2) / q2
    v1, v2 = np.sum(((b1 - m1) ** 2) * p1) / q1, np.sum(((b2 - m2) ** 2) * p2) / q2

    # calculates the minimization function
    fn = v1 * q1 + v2 * q2
    if fn < fn_min:
        fn_min = fn
        thresh = i

# find otsu's threshold value with OpenCV function
ret, otsu = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

print(thresh, ret)