OpenCv 中的【图像阈值化处理】

简介: 正常一个图像分为 R、G、B、三个通道,彩色照片中的每个像素值(生活中的某一中颜色)都是由不同R、G、B的值组合在一起的,比如下面这种

正常一个图像分为 R、G、B、三个通道,彩色照片中的每个像素值(生活中的某一中颜色)都是由不同R、G、B的值组合在一起的,比如下面这种:


网络异常,图片无法展示
|

而 图片去色之后变成灰度图,也就是我们所常见的黑白照片,其实生活中所谓的 "黑白照片"有一定的歧义,仔细观察会发现里面会参杂着不同程度的灰色:

网络异常,图片无法展示
|

真正意义上的 黑白照片 中只有黑色跟白色,要么是白色,要么是黑色;把一张灰度图变成这样的 黑白照片 也称之为 图像的 二值化


图像的二值化一般经过下面几个步骤:


图像灰度图转化,多通道变单通道;

设置阈值,在设置一个新值(介于黑—白之间的颜色),高于这个颜色设为新值,否则设为另外一个颜色;

选择调节方法阈值;

OpenCv 中有分为几类阈值:简单阈值、自适应阈值和 Otsu’s 二值化,其实这几种方法都是关于图像二值化处理:


简单阈值


简单阈值原理,设置一个阈值,高于这个阈值的图像赋予一个新值,低于这个阈值赋予另一种颜色,用到的函数主要是 cv2.threshhold();里面需要用到4个参数:第一个是需要处理的原图像;第二个是 设置的阈值,第三个是需要赋予的新的像素值;第四个参数是 不同的阈值方法:


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_path = 'D:/ceshi.jpg'
img = cv2.imread(img_path)
#灰度图转化;;;
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,th1 = cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY)
ret,th2 = cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY_INV)
ret,th3 = cv2.threshold(img_gray,127,255,cv2.THRESH_TRUNC)
ret,th4 = cv2.threshold(img_gray,127,255,cv2.THRESH_TOZERO)
ret,th5 = cv2.threshold(img_gray,127,255,cv2.THRESH_TOZERO_INV)
titles = ['oringnal','gray_img','BINGARY','BINGARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img,img_gray,th1,th2,th3,th4,th5]
i = 0
for i in range(7):
    plt.subplot(3,3,i+1)
    plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

阈值展示效果如下:

可以从图像中可以很清楚地看到 不同阈值之间的区别与联系;Threshold()函数返回的有两个值,第二个才是我们要的图像

自适应阈值


这一部分选取处理图像如下:

简单阈值又称之为全句阈值,就是整个图像发生改变,图像中的像素值分布只有两种,一种是大于初设的阈值区域,另外一种就是小于初设的阈值,对于图像阈值处理方面具有一定的局限性,OpenCv 中又引入了一种 自适应阈值 方法,使得图像中不同亮度部分最终显示不同效果,

**自适应阈值 ** 是根据图像上 每一小区域来进行计算 其对应阈值,也就是不同区域会设置不同的阈值效果,


OpenCv 中 自适应阈值函数用到的函数为: adaptiveThreshold(),里面包含有6个参数:


第一个跟简单阈值一样,是源图像 img;


第二个就是赋予的新像素值;


第三个为 Adaptive Method 指定计算阈值的方法,有两种:


cv2.ADPTIVE_THRESH_MENA_C:阈值取子相邻区域的平均值;

cv2.ADPTOVE_THRESH_GAUSSIAN_C:阈值取值相邻区域的加权和,权重为一个高斯窗口。

第四个就是需要选用的阈值方法,简单阈值中用到过的,例如:cv2.THRESH_BINARY;


第五个参数为 Block Size —邻域大小(用来计算阈值的区域大小)。


第六个参数 C 是一个常数,阈值就等于的平均值或者加权平均值减去这个常数值;


提醒一下,在做 自适应阈值 之前,需要对图片进行 一下 中值滤波处理 ;计算指定大小区域的平均像素值并把这一区域的像素值统一赋值;


下来可以看一下 自适应阈值 与 简单阈值 之间的区别,以及 自适应阈值 不同计算方法之间的差别:

import cv2
import numpy as np
from matplotlib import pyplot as plt
#图片读入灰度图
img1  =cv2.imread('E:/7.jpg',0)
#中值滤波
img = cv2.medianBlur(img1,5)
#简单阈值
ret, th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,
                            cv2.THRESH_BINARY,11,2)
th3 =cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,
                           cv2.THRESH_BINARY,11,5)
th4 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
th5 =cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,5)
titles = [
    'origianl_ images','means-image','gloabal(v = 127)','Mean(C =2)',
'Mean(C =5)','Gayssian(C = 2)',
'Gayssian(C = 5)'
]
images =[img1,img,th1,th2,th3,th4,th5]
num = 1
for i in range(2,6):
    plt.subplot(2,2,num),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
    num += 1
plt.show()

展示效果:



这里我用到的图片比较模糊,所以展示的效果很差,下面我贴一下官网上的效果图:

网络异常,图片无法展示
|


Otsu’s 二值化


无论是 简单阈值 ,还是 自适应阈值 ,我们在处理之前都不可避免地需要考虑 阈值 设置问题,设置的好坏对于最后成像起到很大的影响,但是怎样设置一最适合的阈值呢?不断尝试?


而这个就是 Ostu 二值化要做的,通过根据图像的直方图分布计算出一个阈值 ,但是对于 非双峰图像来说,这种方法得到的结果可能不太理想,Ostu 二值化 用到的函数同样是 cv2.threshold(),


在之前的 简单阈值 部分中,cv2.threshold() 函数返回了两个值,第二个参数是我们最后要的图像,而第一个 rerval ,其实就是这里我们要计算的的最佳阈值,Ostu二值化 与 **简单阈值 **之间 一个重要的区别,就是需要多传入一个参数:cv2.THRESH_OSTU ,同时把 threshold() 函数中设定的阈值一定要设为 0;

import cv2
import numpy as np
from matplotlib import pyplot as plt
#图片读入灰度图
img1  =cv2.imread('E:/9.jpg',0)
#简单阈值处理
ret1,th1 = cv2.threshold(img1,127,255,cv2.THRESH_BINARY)
#Ostu thresholding
ret2,th2 = cv2.threshold(img1,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Ostu ‘ s thresholding after Gaussian FILTERING
#5,5为高斯核的大小,0为标准差;
blur =cv2.GaussianBlur(img1,(5,5),0)
ret3,th3 =cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
## plot all the images and their histogram
images =[img1,0,th1,
         img1,0,th2,
         blur,0,th3]
titles =[
    'Ori','Hist','Glo(v =127)',
    'Ori', 'Hist', 'Ostu',
    'Gass', 'Hist', 'Ostu',
]
#治理使用 pyplot绘制直方图,参数为一维数组,用到了numpy.ravel()函数;
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()

这里选取一个带有噪点的图像,对于第一、二排是分别对图像做了 简单阈值Ostu二值化 ,而对于第三副图,先对带噪点的图像做了一个高斯核出去噪音,然后再进行 二值化

下面利用 pyplot 函数展示每一排分别代表为:处理之前的图像、未处理的直方图、处理之后的图像;

因为这里处理的元图像很模糊,所以处理之后的效果并不明显,这里贴一张官方的图片:

怎么样是不是很赞,而我处理的原图像就下面这样子。。。。。

网络异常,图片无法展示
|

相关文章
|
7天前
|
计算机视觉 Python
轻松掌握opencv的8种图像变换
轻松掌握opencv的8种图像变换
|
8天前
|
算法 计算机视觉
【OpenCV】- 图像修复
【OpenCV】- 图像修复
|
8天前
|
Serverless 计算机视觉
【OpenCV】-图像的矩
【OpenCV】-图像的矩
|
8天前
|
编解码 物联网 计算机视觉
【OpenCV】—图像金子塔与图片尺寸缩放
【OpenCV】—图像金子塔与图片尺寸缩放
|
8天前
|
前端开发 计算机视觉 C++
【OpenCV】—分离颜色通道、多通道图像混合
【OpenCV】—分离颜色通道、多通道图像混合
|
8天前
|
API 计算机视觉
【OpenCV】—图像对比度、亮度值调整
【OpenCV】—图像对比度、亮度值调整
|
8天前
|
计算机视觉 索引
【OpenCV】—ROI区域图像叠加&图像混合
【OpenCV】—ROI区域图像叠加&图像混合
|
8天前
|
存储 算法 C语言
OpenCV—访问图像中的像素
OpenCV—访问图像中的像素
|
26天前
|
编解码 计算机视觉 Python
opencv 图像金字塔(python)
opencv 图像金字塔(python)
|
26天前
|
边缘计算 算法 计算机视觉
opencv 图像梯度(python)
opencv 图像梯度(python)