OpenCV-图像二值化

图像二值化

简单阈值(OTSU和Triangle)

cv2.threshold

简单阈值

threshold(src, thresh, maxval, type[, dst]) -> retval, dst
  • src:表示的是图片源
  • thresh:表示的是阈值(起始值)
  • maxval:表示的是最大值
  • type:表示的是这里划分的时候使用的是什么类型的算法

注意:

  • 当选择计算方式(如:cv.THRESH_OTSU)之后,前面所定义的thresh会不起作用
  • type参数:图像处理方式 | 阈值计算方法
    • 图像处理方式:cv.THRESH_BINARY、cv.THRESH_BINARY_INV、cv.THRESH_TOZERO等
    • 阈值计算方法:cv.THRESH_OTSU、cv.THRESH_TRIANGLE

在这里插入图片描述

THRESH_BINARY 二进制阈值化 -> 大于阈值为1 小于阈值为0
THRESH_BINARY_INV 反二进制阈值化 -> 大于阈值为0 小于阈值为1
THRESH_TRUNC 截断阈值化 -> 大于阈值为阈值,小于阈值不变
THRESH_TOZERO 阈值化为0 -> 大于阈值的不变,小于阈值的全为0
THRESH_TOZERO_INV 反阈值化为0 -> 大于阈值为0,小于阈值不变

参考链接:

示例

def image_binary(image):
    """图像二值化(简单阈值)"""
    image_gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    # 这个函数的第一个参数就是原图像,原图像应该是灰度图。
    # 第二个参数就是用来对像素值进行分类的阈值。
    # 第三个参数就是当像素值高于(有时是小于)阈值时应该被赋予的新的像素值
    # 第四个参数指定阈值类型(图像处理方式 | cv.THRESH_OTSU、cv.THRESH_TRIANGLE表示使用OTSU、TRIANGLE的阈值计算方法)
    ret, binary = cv.threshold(image_gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
    # ret, binary = cv.threshold(image_gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_TRIANGLE)
    # ret, binary = cv.threshold(image_gray, 0, 255, cv.THRESH_TOZERO | cv.THRESH_OTSU)
    print("threshold value: %s" % ret)
    cv.imshow("threshold_demo", binary)
    cv.imshow("image", image)

结果:
在这里插入图片描述

示例

def image_threshold(image):
    """显示多种图像二值化方法(简单阈值)"""
    image_gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    ret, thresh1 = cv.threshold(image_gray, 127, 255, cv.THRESH_BINARY)
    ret, thresh2 = cv.threshold(image_gray, 127, 255, cv.THRESH_BINARY_INV)
    ret, thresh3 = cv.threshold(image_gray, 127, 255, cv.THRESH_TRUNC)
    ret, thresh4 = cv.threshold(image_gray, 127, 255, cv.THRESH_TOZERO)
    ret, thresh5 = cv.threshold(image_gray, 127, 255, cv.THRESH_TOZERO_INV)
    titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
    images = [image, thresh1, thresh2, thresh3, thresh4, thresh5]
    for i in range(6):
        plt.subplot(2, 3, i + 1), plt.imshow(images[i], cmap='gray')  # 将图像按2x3铺开,以灰度图的方式显示
        plt.title(titles[i])
        plt.xticks([]), plt.yticks([])
    plt.show()

结果:
在这里插入图片描述

注意: plt.imshow默认是带点绿色的图,想要显示灰度图需要传参cmap=‘gray’。
参考链接:

自适应阈值

在前面的部分我们使用是全局阈值,整幅图像采用同一个数作为阈值。

当时这种方法并不适应与所有情况,尤其是当同一幅图像上的不同部分的具有不同亮度时。这种情况下我们需要采用自适应阈值。此时的阈值是根据图像上的每一个小区域计算与其对应的阈值。

因此在同一幅图像上的不同区域采用的是不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果。

cv2.adaptiveThreshold

自适应阈值

 adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C[, dst]) -> dst
  • adaptiveMethod:Int类型的,这里有两种选择,不过这两种方法最后得到的结果要减掉参数里面的C值。

    • ADAPTIVE_THRESH_MEAN_C(通过平均的方法取得平均值)———阈值取自相邻区域的平均值)
    • ADAPTIVE_THRESH_GAUSSIAN_C(通过高斯取得高斯值)———阈值取自相邻区域的加权和
  • thresholdType:同type,见threshold

  • blockSize:Int类型的,这个值来决定像素的邻域块有多大。

  • C:偏移值调整量,计算adaptiveMethod用到的参数。

注意: 这里的blockSize的值要为奇数,否则会给出这样的提示:
Assertion failed (blockSize % 2 == 1 && blockSize > 1) in cv::adaptiveThreshold

参考链接:

示例

def threshold_adaptive(image):
    """图像二值化(自适应阈值)"""
    img = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    # 中值滤波
    img = cv.medianBlur(img, 5)
    ret, th1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
    # 11 为 Block size, 2 为 C 值
    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], cmap='gray')
        plt.title(titles[i])
        plt.xticks([]), plt.yticks([])

    plt.show()

结果:
在这里插入图片描述

手动计算阈值

手动将图像二值化

示例

def threshold_custom(image):
    """手动将图像二值化"""
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    h, w = gray.shape[:2]
    m = np.reshape(gray, [1, w*h])
    mean = m.sum() / (w*h)  # 求出整个灰度图像的平均值
    print("mean:", mean)
    ret, binary = cv.threshold(gray, mean, 255, cv.THRESH_BINARY)
    cv.imshow("threshold_custom", binary)

结果:
在这里插入图片描述

大图像二值化

示例

def big_image_threshold(image):
    """大图像二值化"""
    print(image.shape)
    cw = 256  # cw、ch定义分隔的小块的大小
    ch = 256
    h, w = image.shape[:2]
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    # cv.imshow("big_image_gray", gray)

    for row in range(0, h, ch):  # 分割图片
        for col in range(0, w, cw):
            roi = gray[row:row+ch, col:col+cw]  # 获取ROI(坐标为row,col的256*256的小矩形)
            # 对ROI区域进行图像二值化(自适应阈值),127是256/2,将ROI分割成四个小区域分别进行
            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))  # 打印ROI区域的标准差和平均值

    cv.imwrite("result_big_image.jpg", gray)  # 保存图像

结果:
分辨率:1000 * 1398(在windows上显示的宽高,OpenMV里是1398 * 1000)
在这里插入图片描述
分辨率:2362 * 3425(在windows上显示的宽高,OpenMV里是3425 * 2362)
在这里插入图片描述

对该算法进行优化:

def big_image_threshold_pro(image):
    """优化大图像二值化"""
    print(image.shape)
    cw = 600  # cw、ch定义分隔的小块的大小
    ch = 600
    h, w = image.shape[:2]
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    # cv.imshow("big_image_gray", gray)

    for row in range(0, h, ch):  # 分割图片
        for col in range(0, w, cw):
            roi = gray[row:row + ch, col:col + cw]  # 获取ROI(坐标为row,col的256*256的小矩形)
            # 对ROI区域进行图像二值化(自适应阈值)
            dst = cv.adaptiveThreshold(roi, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 299, 2)
            if np.std(dst) <= 60:
                gray[row:row + ch, col:col + cw] = 255
            else:
                gray[row:row + ch, col:col + cw] = dst
            print(np.std(dst), np.mean(dst))  # 打印ROI区域的标准差和平均值

    cv.imwrite("result_big_imagePro.jpeg", gray)  # 保存图像

个人优化后结果(与优化前做对比):
在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咬着棒棒糖闯天下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值