[转载] python3 opencv 图像二值化笔记(cv2.adaptiveThreshold)

参考链接: python opencv 基础6: cv2.threshold()二值图像

前一篇研究了opencv二值化方法threshold的使用,但是这个方法也存在一定的局限性,假如有一张图存在明显的明暗不同的区域,如下图 

 

可以看到左边部分因为整体偏暗,导致二值化后变成全黑,丢失了所有细节,这显然不是我们想要的结果。 

原因threshold函数使用一个阈值对图像进行二值化,导致小于这个阈值的像素点全都变成0。因此使用一个阈值的二值化方法并不适用于上面的这张图。那怎么搞? 

很明显,上面这张图只有左右两个区域明显亮度不同,最简单的方法就是把图分成两个区域,每个区域分别进行二值化,也就是说二值化上面这张图需要两个不同的阈值。那如果亮度不同的地方有三个,四个或者更多呢?那就每个区域用一个阈值来进行二值化。按照这个思想,因此有了cv2.adaptiveThreshold函数。 

先看一下adaptiveThreshold二值化的使用效果。 

 

明显还是有效果的,至少左边部分不是全黑。 

接下来简单说一下adaptiveThreshold方法 

cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C, dst=None) 

这个函数大致意思就是把图片每个像素点作为中心取N*N的区域,然后计算这个区域的阈值,来决定这个像素点变0还是变255 

src:需要进行二值化的一张灰度图像 

maxValue:满足条件的像素点需要设置的灰度值。(将要设置的灰度值) 

adaptiveMethod:自适应阈值算法。可选ADAPTIVE_THRESH_MEAN_C 或 ADAPTIVE_THRESH_GAUSSIAN_C 

thresholdType:opencv提供的二值化方法,只能THRESH_BINARY或者THRESH_BINARY_INV 

blockSize:要分成的区域大小,上面的N值,一般取奇数 

C:常数,每个区域计算出的阈值的基础上在减去这个常数作为这个区域的最终阈值,可以为负数 

dst:输出图像,可以忽略 

前两个参数与threshold的src和maxval一样相同 

第三个参数adaptiveMethod 

提供两种不同的计算阈值的方法,按照网上其他大佬的解释 

 

 ADAPTIVE_THRESH_MEAN_C,为局部邻域块的平均值,该算法是先求出块中的均值。 

 ADAPTIVE_THRESH_GAUSSIAN_C,为局部邻域块的高斯加权和。该算法是在区域中(x, y)周围的像素根据高斯函数按照他们离中心点的距离进行加权计算。 

 

 第四个参数thresholdType 

只能THRESH_BINARY或者THRESH_BINARY_INV 

第5个参数blockSize 

上述算法计算邻域时的领邻域大小,一般选择为3、5、7......等 

第6个参数C 

每个邻域计算出阈值后再减去C作为最终阈值 

演示一下blockSize和C对二值化结果的影响,以THRESH_BINARY,ADAPTIVE_THRESH_GAUSSIAN_C为例 

 

 

 

  blockSize=3,C=1

 

 

  

 

 

 

  blockSize=25,C=1

 

 

 

 

 

  blockSize=3,C=10

 

 

  

 

 

 

  blockSize=15,C=10

 

 

  

 

 

 

  blockSize=15,C=21

 

 

 

 

 

  blockSize=15,C=1

 

 

  

 

 

 

  blockSize=15,C=1

 

 

 可以看到,当blockSize越大,参与计算阈值的区域也越大,细节轮廓就变得越少,整体轮廓越粗越明显 

当C越大,每个像素点的N*N邻域计算出的阈值就越小,中心点大于这个阈值的可能性也就越大,设置成255的概率就越大,整体图像白色像素就越多,反之亦然。 

这种二值化有点类似canny边缘检测,用来找轮廓或者特征点也挺不错。 

import cv2

import numpy as np

 

blocksize = 3

C=0

def adaptive_demo(gray, blocksize, C):

    binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, blocksize, C)

    # binary = cv2.GaussianBlur(binary, (15,15), 0)

    cv2.imshow('binary', binary)

 

def C_changed(value):

    global gray

    global blocksize

    global C

    C = value - 30

    print('C:', C)

    adaptive_demo(gray, blocksize, C)

 

def blocksize_changed(value):

    global gray

    global blocksize

    global C

    blocksize = 2 * value + 1

 

    print('blocksize:', blocksize)

    adaptive_demo(gray, blocksize, C)

 

if __name__ == "__main__":

    image_path = './img/1.jpg'

    img = cv2.imread(image_path)

 

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

 

    adaptive_demo(gray, 3, 0)

    cv2.createTrackbar('C', 'binary',0, 60, C_changed)

    cv2.createTrackbar('blocksize', 'binary',1, 20, blocksize_changed)

 

    cv2.waitKey(0)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是Python使用OpenCV实现cv2.adaptiveThreshold()函数的源代码: ``` import cv2 # 读取图像 img = cv2.imread('image.png', 0) # 设置阈值和阈值类型 max_value = 255 adaptive_method = cv2.ADAPTIVE_THRESH_MEAN_C threshold_type = cv2.THRESH_BINARY block_size = 11 constant = 2 # 自适应阈值处理 thresh = cv2.adaptiveThreshold(img, max_value, adaptive_method, threshold_type, block_size, constant) # 显示处理结果 cv2.imshow('Adaptive Threshold', thresh) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在这段代码,首先使用cv2.imread()函数读取一张灰度图像。接下来,设置了阈值和阈值类型,包括最大值、自适应方法、阈值类型、块大小和常数。最后使用cv2.adaptiveThreshold()函数进行自适应阈值处理,并将处理结果显示出来。 ### 回答2: ```python import numpy as np def adaptiveThreshold(img, maxValue, adaptiveMethod, thresholdType, blockSize, C): """ 实现opencvcv2.adaptiveThreshold()函数。 参数: - img: 输入图像 - maxValue: 输出图像超过阈值的像素值 - adaptiveMethod: 阈值计算的方法,取值为cv2.ADAPTIVE_THRESH_MEAN_C或cv2.ADAPTIVE_THRESH_GAUSSIAN_C - thresholdType: 阈值类型,取值为cv2.THRESH_BINARY或cv2.THRESH_BINARY_INV - blockSize: 邻域大小(奇数),用于计算阈值 - C: 从均值或加权均值减去的常数 返回值: - 输出图像 """ # 获取图像的高度和宽度 h, w = img.shape # 创建与输入图像相同大小的输出图像 output = np.zeros((h, w), dtype=np.uint8) # 遍历图像的每个像素 for i in range(h): for j in range(w): # 获取当前像素的邻域 if i - blockSize // 2 < 0 or j - blockSize // 2 < 0 or i + blockSize // 2 >= h or j + blockSize // 2 >= w: # 邻域超出图像范围的处理方式 output[i, j] = 0 else: # 邻域内像素的平均值或加权平均值 if adaptiveMethod == cv2.ADAPTIVE_THRESH_MEAN_C: threshold = np.mean(img[i-blockSize//2:i+blockSize//2+1, j-blockSize//2:j+blockSize//2+1]) elif adaptiveMethod == cv2.ADAPTIVE_THRESH_GAUSSIAN_C: threshold = np.mean(img[i-blockSize//2:i+blockSize//2+1, j-blockSize//2:j+blockSize//2+1]) else: raise ValueError("Invalid adaptive method!") # 二值化像素值 if img[i, j] > threshold - C: output[i, j] = maxValue else: output[i, j] = 0 # 根据阈值类型对输出图像进行相应的处理 if thresholdType == cv2.THRESH_BINARY_INV: output = cv2.bitwise_not(output) return output ``` 这段代码实现OpenCV的`cv2.adaptiveThreshold()`函数。它通过传入的参数来计算图像的自适应阈值,并根据阈值类型对图像进行二值化处理。代码首先创建一个与输入图像大小相同的输出图像,然后遍历图像的每个像素。对于每个像素,根据邻域大小计算出邻域内像素的平均值或加权平均值作为阈值,并根据阈值类型进行二值化处理。最后,根据是否选择了`cv2.THRESH_BINARY_INV`阈值类型对输出图像进行相应的处理。最后,返回输出图像。 ### 回答3: 对于给定的图像和自适应阈值方法,cv2.adaptiveThreshold()函数可以根据输入的参数计算并应用自适应阈值,并将结果图像返回。 下面是一个用Python实现的伪代码示例: ``` import cv2 import numpy as np def adaptiveThreshold(image, maxValue, adaptiveMethod, thresholdType, blockSize, C): # 获取图像的尺寸 height, width = image.shape # 初始化输出图像 output = np.zeros((height, width), np.uint8) # 循环遍历图像的每个像素点 for i in range(height): for j in range(width): # 计算当前像素点的局部区域 top = max(0, i - blockSize // 2) bottom = min(height - 1, i + blockSize // 2) left = max(0, j - blockSize // 2) right = min(width - 1, j + blockSize // 2) neighborhood = image[top:bottom + 1, left:right + 1] # 根据自适应方法计算局部区域的阈值 if adaptiveMethod == cv2.ADAPTIVE_THRESH_MEAN_C: threshold = np.mean(neighborhood) - C elif adaptiveMethod == cv2.ADAPTIVE_THRESH_GAUSSIAN_C: threshold = np.mean(neighborhood) - C * np.std(neighborhood) # 根据阈值和阈值类型对当前像素点进行二值化 if image[i, j] > threshold: output[i, j] = maxValue else: output[i, j] = 0 # 返回二值化结果图像 return output ``` 这段代码首先传入图像、最大值、自适应阈值方法、阈值类型、块大小和常数值。 然后,代码创建一个与输入图像大小相同的输出图像,并应用了一个嵌套的循环来遍历图像的每个像素点。 在每个像素点处,代码计算了该像素点周围局部区域的阈值,该阈值根据选择的自适应方法和常数值计算得到。 最后,根据阈值和阈值类型,代码对当前像素点进行二值化,并将二值化结果保存在输出图像。 最后,代码返回输出图像作为函数的结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值