OpenCV——图像二值化

前言

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

正文

原理

获取阈值的原理

在这里插入图片描述

重要函数:cv.threshold

在这里插入图片描述

#这个函数的第一个参数就是原图像,原图像应该是灰度图。
#第二个参数就是用来对像素值进行分类的阈值。
#第三个参数就是当像素值高于(有时是小于)阈值时应该被赋予的新的像素值
#第四个参数来决定阈值方法

threshold中type的参数

在这里插入图片描述
比如说我这里解释一个:THRESH_BINARY。这个函数就是当过门限的值为最大值,其他值为0。其他就可以参照这些进行解释了,具体的效果如何可能还是会依据你不同图像的特征进行效果不同。

全局阈值

效果图

在这里插入图片描述

函数如下

def thresold_simple(image):
    img = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    ret,thresh1 = cv.threshold(image,127,255,cv.THRESH_BINARY)
    ret, thresh2 = cv.threshold(img, 127, 255, cv.THRESH_BINARY_INV)
    ret, thresh3 = cv.threshold(img, 127, 255, cv.THRESH_TRUNC)
    ret, thresh4 = cv.threshold(img, 127, 255, cv.THRESH_TOZERO)
    ret, thresh5 = cv.threshold(img, 127, 255, cv.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')  # 将图像按2x3铺开
        plt.title(titles[i])
        plt.xticks([]), plt.yticks([])
    plt.show()

局部阈值

说明:

在前面的部分我们使用是全局阈值,整幅图像采用同一个数作为阈值。
当时这种方法并不适应与所有情况,尤其是当同一幅图像上的不同部分的具有不同亮度时。
这种情况下我们需要采用自适应阈值。此时的阈值是根据图像上的 每一个小区域计算与其对应的阈值。
因此在同一幅图像上的不同区域采用的是不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果。
这种方法需要我们指定三个参数,返回值只有一个
_MEAN_C:阈值取自相邻区域的平均值,_GAUSSIAN_C:阈值取值相邻区域 的加权和,权重为一个高斯窗口。
Block Size - 邻域大小(用来计算阈值的区域大小)。
C - 这就是是一个常数,阈值就加等于的平均值或者权平均值减去这个常数。

使用的函数为:cv2.adaptiveThreshold()

第一个原始图像
第二个像素值上限
第三个自适应方法Adaptive Method:
— cv2.ADAPTIVE_THRESH_MEAN_C :领域内均值
—cv2.ADAPTIVE_THRESH_GAUSSIAN_C :领域内像素点加权和,权 重为一个高斯窗口
第四个值的赋值方法:只有cv2.THRESH_BINARY 和cv2.THRESH_BINARY_INV
第五个Block size:规定领域大小(一个正方形的领域)
第六个常数C,阈值等于均值或者加权值减去这个常数(为0相当于阈值 就是求得领域内均值或者加权值)
这种方法理论上得到的效果更好,相当于在动态自适应的调整属于自己像素点的阈值,而不是整幅图像都用一个阈值。

效果图

在这里插入图片描述
code:

def threshold_demo(image):
    img = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    # 中值滤波(基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值,让周围的像素值接近真实的值从而消除孤立的噪声点。)
    img = cv.medianBlur(img, 5)
    ret, th1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
    th2 = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 11, 2)
    th3 = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 11, 2)

    titles = ['Original Image', 'Global Threshold (v = 127)', 'Adaptive Mean Threshold', 'Adaptive Gaussian Threshold']
    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()
    # 第一个原始图像
    # 第二个像素值上限
    # 第三个自适应方法Adaptive
    # Method:
    # — cv2.ADAPTIVE_THRESH_MEAN_C :领域内均值
    # —cv2.ADAPTIVE_THRESH_GAUSSIAN_C :领域内像素点加权和,权
    # 重为一个高斯窗口
    # 第四个值的赋值方法:只有cv2.THRESH_BINARY
    # 和cv2.THRESH_BINARY_INV
    # 第五个Block
    # size: 规定领域大小(一个正方形的领域)
    # 第六个常数C,阈值等于均值或者加权值减去这个常数(为0相当于阈值
    # 就是求得领域内均值或者加权值)
    # 这种方法理论上得到的效果更好,相当于在动态自适应的调整属于自己像素点的阈值,而不是整幅图像都用一个阈值。

图片全部像素的平均值作为阈值

效果图

在这里插入图片描述

方法

  1. 读取函数
  2. 灰度化
  3. 重新定义了原张量的阶数,弄成了1行w*h列的一个向量了
  4. 求出整个灰度图像的平均值
  5. 求出灰度图像根据该阈值进行的灰度化

代码

def threshold_custome(image):
    gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    h,w = gray.shape[:2]#去shape中的前两个通道
    m = np.reshape(gray,[1,w*h])#reshape()函数重新定义了原张量的阶数,弄成了1行w*h列的一个向量了。
    mean = m.sum()/(w*h)#求出整个灰度图像的平均值
    print("mean:",mean)
    ret,binary = cv.threshold(gray,mean,255,cv.THRESH_BINARY)
    # 这个函数的第一个参数就是原图像,原图像应该是灰度图。
    # 第二个参数就是用来对像素值进行分类的阈值。
    # 第三个参数就是当像素值高于(有时是小于)阈值时应该被赋予的新的像素值
    # 第四个参数来决定阈值方法
    cv.imshow("thresold_custome",binary)

超大图像二值化

效果图

在这里插入图片描述

方法

  1. 图像灰度化
  2. 将图像全部像素点进行循环,一个小块一个小块的走。然后,对这小块进行自适应。再把自适应好的图片小块重新进行赋值。
  3. 将图片写入固定的位置。

函数

  1. 自适应阈值化——cv::adaptiveThreshold()
    上述的二值化本质上还是全局二值化,重点在于如何获取最佳阈值,这次我们讲解一种局部阈值方式,即opencv集成的自适应二值化。自适应阈值化能够根据图像不同区域亮度分布的,改变阈值。
void cv::adaptiveThreshold(  
    cv::InputArray src, // 输入图像  
    double maxValue, // 向上最大值  
    int adaptiveMethod, // 自适应方法,平均或高斯  
    int thresholdType // 阈值化类型  
    int blockSize, // 块大小  
    double C // 常量  
);

cv::adaptiveThreshold()支持两种自适应方法,即cv::ADAPTIVE_THRESH_MEAN_C(平均)和cv::ADAPTIVE_THRESH_GAUSSIAN_C(高斯)。在两种情况下,自适应阈值T(x, y)。通过计算每个像素周围bxb大小像素块的加权均值并减去常量C得到。其中,b由blockSize给出,大小必须为奇数;如果使用平均的方法,则所有像素周围的权值相同;如果使用高斯的方法,则(x,y)周围的像素的权值则根据其到中心点的距离通过高斯方程得到。

代码

# 将大图片拆分成小图片后再用自适应局部阈值比较好
def big_image_demo(image):
    print(image.shape)
    cw = 200
    ch = 200
    h, w = image.shape[:2]
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    cv.imshow("big_image_demo_gray", gray)

    # 将一张图片每隔ch * cw分成一份
    for row in range(0, h, ch):
        for col in range(0, w, cw):
            roi = gray[row:row+ch, col:col+cw]
            dst = cv.adaptiveThreshold(roi, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 127, 2)
            gray[row:row + ch, col:col + cw] = dst
            print(np.std(dst), np.mean(dst))

    cv.imwrite("../images/result_big_image.png", gray)

参考博客

  1. OpenCV—图像二值化
  2. python+opencv3.3视频教学 基础入门
  3. 图像阈值化-threshold、adaptivethreshold
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值