opencv 图像阈值

简单阈值 cv2.threshhold()

简单阈值处理一般处理的是灰度图像,输出是二值图像。简单阈值处理,就是遍历图像中的每一个像素,判断像素与阈值大小,大于阈值或者小于阈值,都会赋予一个新值。
'''
简单阈值
像素值高于阈值时 我们给这个像素 赋予一个新值, 可能是白色 ,
 否则我们给它赋予另外一种颜色, 或是黑色 。
 这个函数就是 cv2.threshhold()。
 这个函数的第一个参数就是原图像
 原图像应是灰度图。
 第二个参数就是用来对像素值进行分类的阈值。
 第三个参数 就是当像素值高于, 有时是小于  阈值时应该被赋予的新的像素值。
 OpenCV 提供了多种不同的阈值方法 , 是由第四个参数来决定的。
  些方法包括
• cv2.THRESH_BINARY
• cv2.THRESH_BINARY_INV • cv2.THRESH_TRUNC
• cv2.THRESH_TOZERO
• cv2.THRESH_TOZERO_INV
'''

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('img1.png',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()

 自适应阈值 cv2.adaptiveThreshold()

上面使用的全局阈值,整幅图片采用同一个数作为阈值。但是这种方法不适应所有情况,尤其是同一幅图片的不同部分的具有不同亮度的时候。这时需要根据图像上的一个小区域计算对应的阈值。

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

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('img1.png', 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()

 

 Otsu 二值化

全局阈值,是随便使用一个数做阈值,但是怎么判断阈值的好坏呢?

Otsu二值化,同样使用cv2.threshold(),但是需要传入一个flag (cv2.THRESH_OTSU),把阈值设为0.然后算法会找到最优的阈值。这种方法对于双峰图像效果比较好,但是对于非双峰图像,这种方法效果不好。

'''
Otsu's 二值化
简单来说,就是对一副双峰图像自动根据其直方图计算出一个阈值。
对于非双峰图像 这 种方法 得到的结果可能会不理想 。
这里 用到的函数 是 cv2.threshold() 但是  需要多传入一个参数  flag  cv2.THRESH_OTSU。
这时 把 值 为 0。然后算法会找到最 优阈值 ,这 个最优 值就是 回值 retVal。
如果不使用 Otsu 二值化 返回的retVal 值与 设定的 阈值相等。
下 的例子中  输入图像是一副带有噪声的图像。
第一种方法 我们 设127 为全局 阈值。
第二种方法 我们直接使用 Otsu 二值化。
第三种方法 我 们 先使用一个 5x5 的 高斯核 去噪  然后再使用 Otsu 二值化。
看看噪音 去除对结果的影响有多大吧。
'''

import cv2
import numpy as np
from matplotlib import pyplot as plt

def gasuss_noise(image, mean=0, var=0.01):
    '''
        添加高斯噪声
        mean : 均值
        var : 方差
    '''
    image = np.array(image/255, dtype=float)
    ##生成均值,方差的类似Image矩阵
    noise = np.random.normal(mean, var ** 0.5, image.shape)
    out = image + noise
    if out.min() < 0:
        low_clip = -1.
    else:
        low_clip = 0.
    out = np.clip(out, low_clip, 1.0)
    out = np.uint8(out*255)
    return out

img = cv2.imread('img1.png', 0)
# global thresholding
ret1, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
# Otsu's thresholding 这里这个0不管用,这里使用的OTSU寻找最优阈值。这个对于原始图像的自适应阈值处理
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)
ret4,th4= cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 阀值一定为 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,th4,
          blur, 0, th3]
titles = ['Original Noisy Image', 'Histogram', 'Global Thresholding (v=127)',
          'Original Noisy Image', 'Histogram', "Otsu's Thresholding",
          'Noisy Image','Histogram',"Otsu's Thresholding",
          'Gaussian filtered Image', 'Histogram', "Otsu's Thresholding"]
# 使用了 pyplot 中画直方图的方法 plt.hist,
# 注意的是它的参数是一维数组
# 所以使用了 numpy ravel 方法 将多维数组 换成一维 也可以使用 flatten 方法

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

OTSU的原理 

import cv2
import numpy as np

img = cv2.imread('img1.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)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一壶浊酒..

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

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

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

打赏作者

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

抵扣说明:

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

余额充值