图像的阈值处置惩罚定义 :将图像转化为二值图像(黑白图), 也可以用于彩色图形,达到夸张的效果
目的:是用来提取图像中的目标物体,将背景和噪声区分开(可以近似的认为除了目标全是噪声)。
阈值处置惩罚方法:通常会设定一个阈值 T ,通过 T 将图像的像素划分为两类:大于 T 的像素群和小于 T 的像素群。
- 先将图像转化为灰度图像,由于在灰度图像中,每个像素都只有一个灰度值用来表示当前像素的亮度。
- 接下来二值化处置惩罚:即将图像中的像素划分为两类颜色,一种是大于阈值 T 的,另一种是小于阈值 T 的。
应用:图像预处置惩罚(滤波)--->图像分割--->图像辨认
应用示例:分离对应于我们想要分析的对象的图像的区域。该分离基于对象像素和背景像素之间的强度变革。
为了区分我们感兴趣的像素(其最终将被拒绝),我们对每个像素强度值相对于阈值进行比较(根据要办理的问题确定)。
一旦我们精确分离了紧张的像素,我们可以用一个确定的值来设置它们来辨认它们(即我们可以为它们分配值(黑色),(白色)或得当您需要的任何值)
在 OpenCV 中,为我们提供了阈值函数 threshold()来帮助我们实现二值图像的处置惩罚。
函数如下:
- retval, dst = cv2.threshold(src, thresh, maxval, type, dst=None)
复制代码
- retval: 阈值
- dst: 处置惩罚后的图像
- src: 原图像
- thresh: 阈值
- maxval: 最大值
- type: 处置惩罚类型
常用的 5 中处置惩罚类型如下:
- cv2.THRESH_BINARY: 二值处置惩罚
- cv2.THRESH_BINARY_INV: 反二值处置惩罚
- cv2.THRESH_TRUNC: 截断阈值化
- cv2.THRESH_TOZERO: 阈值化为 0
- cv2.THRESH_TOZERO_INV: 反阈值化为 0
一、二值化处置惩罚(非黑即白)
这种二值处置惩罚方式最开始需要选定一个阈值 Threshold,从 0 ~ 255 之间, 这里选择出于中间的谁人数127 。
接下来的处置惩罚规则就是这样的:
像素值<= 阈值 Threshold: 像素值 = 0,即设定为纯黑色
像素值>= 阈值 Threshold: 像素值 = 最大值
接下来开始写代码
- import cv2 as cv
- src = cv.imread("maliao.jpg") # BGR 图像转灰度
- gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
- # 二值图像处理
- Threshold = 127
- r, b = cv.threshold(gray_img, Threshold, 255, cv.THRESH_BINARY)
- # 显示图像 cv.imshow("src", src) cv.imshow("result", b)
- # 等待显示 cv.waitKey(0) cv.destroyAllWindows()
复制代码
二、 反二值处置惩罚
这种方式和上面的二值处置惩罚非常相似,只是把处置惩罚规则给反了一下:
- 像素值<= 阈值 Threshold: 像素值 =最大值
- 像素值>= 阈值 Threshold: 像素值 = 0,即设定为纯黑色
- import cv2 as cv
- src = cv.imread("maliao.jpg")
- # BGR 图像转灰度
- gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
- # 二值图像处理
- r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_BINARY_INV)
- # 显示图像
- cv.imshow("src", src) cv.imshow("result", b)
- # 等待显示 cv.waitKey(0) cv.destroyAllWindows()
复制代码
从图像上可以看到,颜色和上面的二值图像正好相反,大部门的位置都变成了白色。
三、截断阈值化
这种方法还是需要先选定一个阈值 T ,图像中大于该阈值的像素点被设定为该阈值,小于该阈值的保持不变。
完整代码如下:
- import cv2 as cv
- src = cv.imread("maliao.jpg")
- # BGR 图像转灰度
- gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
- # 二值图像处理
- r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_TRUNC)
- # 显示图像 cv.imshow("src", src) cv.imshow("result", b)
- # 等待显示 cv.waitKey(0) cv.destroyAllWindows()
复制代码
这种方式实际上是把图片比较亮的像素处置惩罚成为阈值,其他部门保持不变。
四、阈值化为 0
这种方式还是需要先选定一个阈值 T ,将小于 T 的像素点设置为 0 黑色,其他的保持不变。
完整代码如下:
- import cv2 as cv
- src = cv.imread("maliao.jpg")
- # BGR 图像转灰度
- gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
- # 二值图像处理
- r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO)
- # 显示图像
- cv.imshow("src", src) cv.imshow("result", b)
- # 等待显示
- cv.waitKey(0) cv.destroyAllWindows()
复制代码
这个方法是亮的部门不改,把比较暗的部门修改为 0 。
这个和前面的反二值图像很像,同样是反阈值化为 0 ,将大于等于 T 的像素点变为 0 ,别的保持不变。
完整代码如下:
- import cv2 as cv
- src = cv.imread("maliao.jpg")
- # BGR 图像转灰度
- gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
- # 二值图像处理
- r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO_INV)
- # 显示图像
- cv.imshow("src", src)
- cv.imshow("result", b)
- # 等待显示
- cv.waitKey(0)
- cv.destroyAllWindows()
复制代码
接下来还是给这几种阈值处置惩罚后的图像来个百口福,让各人能有一个直观的感受,代码如下:
- import cv2 as cv
- import matplotlib.pyplot as plt
- # 读取图像
- img=cv.imread('maliao.jpg')
- lenna_img = cv.cvtColor(img,cv.COLOR_BGR2RGB)
- gray_img=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
- # 阈值化处理
- ret1, thresh1=cv.threshold(gray_img, 127, 255, cv.THRESH_BINARY)
- ret2, thresh2=cv.threshold(gray_img, 127, 255, cv.THRESH_BINARY_INV)
- ret3, thresh3=cv.threshold(gray_img, 127, 255, cv.THRESH_TRUNC)
- ret4, thresh4=cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO)
- ret5, thresh5=cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO_INV)
- # 显示结果
- titles = ['Gray Img','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
- images = [gray_img, thresh1, thresh2, thresh3, thresh4, thresh5]
- # matplotlib 绘图:可以同时显示多个图像,而且图像显示在命令窗口上,而不是以窗口弹出的方式显
- 示
- 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()
复制代码
举例2:同时显示多种阈值化操纵后的图像
- import cv2 as cv
- import matplotlib.pyplot as plt
- # 读取图像
- img=cv.imread('C:\\Users\\seewo\\Desktop\\OpenCV\\photo\\beauty11.jpeg')
- #lenna_img = cv.cvtColor(img,cv.COLOR_BGR2RGB)
- #gray_img=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
- gray_img = img
- # 阈值化处理
- TH = 200
- ret1, thresh1=cv.threshold(gray_img, TH, 255, cv.THRESH_BINARY)
- ret2, thresh2=cv.threshold(gray_img, TH, 255, cv.THRESH_BINARY_INV)
- ret3, thresh3=cv.threshold(gray_img, TH, 255, cv.THRESH_TRUNC)
- ret4, thresh4=cv.threshold(gray_img, TH, 255, cv.THRESH_TOZERO)
- ret5, thresh5=cv.threshold(gray_img, TH, 255, cv.THRESH_TOZERO_INV)
- # 显示结果
- titles = ['Gray Img','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
- images = [gray_img, thresh1, thresh2, thresh3, thresh4, thresh5]
- # 封装图片显示函数:解决关闭窗口后,程序阻塞问题
- def showImage(img, title='image', t=3000, esc=False):
- cv.imshow(title, img)
- if esc:
- while cv.waitKey(100) != 27:
- if cv.getWindowProperty(title,cv.WND_PROP_VISIBLE)<=0:# 如果图像窗口被
- 关闭,则不用等待用户按键,直接跳出
- break
- else:
- cv.waitKey(t)
- cv.destroyWindow(title) # 跳出后,关闭图像
- showImage(thresh1, title='THRESH_BINARY', t=0, esc=False) # 二值化
- showImage(thresh2, title='THRESH_BINARY_INV', t=0, esc=False) # 反二值化
- showImage(thresh3, title='THRESH_TRUNC', t=0, esc=False) # 截断:图像整体变
- 暗,降低亮度的同时,浅颜色变得更浅
- showImage(thresh4, title='TOZERO', t=0, esc=False) # 阈值化为0(低于阈
- 值0处理):深颜色沉底变黑,浅颜色不受影响
- showImage(thresh5, title='THRESH_TOZERO_INV', t=0, esc=False) # 反阈值化为0(大于
- 阈值0处理):浅颜色沉底变黑,深颜色不受影响
复制代码 五、自适应阈值:
当同一幅图像上的不同部门的具有不同亮度时。这种情况下我们需要接纳自适应阈值。此时的阈值是根据图像上的每一个小区域计算与其对应的阈值。因此在同一幅图像上的不同区域接纳的是不同的阈值,从而使我们能在亮度不同的情况下得到更好的效果。
- cv2.adaptiveThreshold(src, maxValue, adaptive_method, threshold_type, block_size,C )
复制代码参数:
src
| 原图像,原图像应该是灰度图。
| maxValue
| 像素值高于(有时是小于)阈值时应该被赋予的新的像素值
|
adaptive_method
| 自适应阈值计算方法:CV_ADAPTIVE_THRESH_MEAN_C(均值) 或
CV_ADAPTIVE_THRESH_GAUSSIAN_C(高斯加权)
| threshold_type
| 阈值类型:CV_THRESH_BINARY 或 CV_THRESH_BINARY_INV
| block_size
| 正方形区域:用来计算阈值的象素邻域大小: 3x3, 5x5, 7x7
| C 常数
| CV_ADAPTIVE_THRESH_MEAN_C: 块中的均值(mean) - C
|
| CV_ADAPTIVE_THRESH_MEAN_C: 块中的加权和(gaussian) - C
|
在图像阈值化操纵中,更关注的是从二值化图像中,分离目标区域和背景区域,但是仅仅通过设定固定阈值很难达到理想的分割效果。
在前面的部门我们使用是全局阈值,整幅图像接纳同一个数作为阈值。当时这种方法并不适应与所有情况,尤其是当同一幅图像上的不同部门的具有不同亮度时。这种情况下我们需要接纳自适应阈值。此时的阈值是根据图像上的每一个小区域计算与其对应的阈值。因此在同一幅图像上的不同区域接纳的是不同的阈值,从而使我们能在亮度不同的情况下得到更好的效果。
自适应阈值,则是根据像素的邻域块的像素值分布来确定该像素位置上的二值化阈值。这样做的好处:
- 每个像素位置处的二值化阈值不是固定不变的,而是由其周围邻域像素的分布来决定的。
- 亮度较高的图像区域的二值化阈值通常会较高,而亮度低的图像区域的二值化阈值则会相适应的变小。
- 不同亮度、对比度、纹理的局部图像区域将会拥有相对应的局部二值化阈值。
- 得当处置惩罚光照不均的图像。
- Python+opencv代码:
- import cv2
- image = cv2.imread("flower3.jpeg") # 读取4.27.png
- image_Gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 将4.27.png转换为灰度图像
- # 自适应阈值的计算方法为cv2.ADAPTIVE_THRESH_MEAN_C
- athdMEAM = cv2.adaptiveThreshold\
- (image_Gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 5, 3)
- # 自适应阈值的计算方法为cv2.ADAPTIVE_THRESH_GAUSSIAN_C
- athdGAUS = cv2.adaptiveThreshold\
- (image_Gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY, 5, 3)
- # 显示自适应阈值处理的结果
- cv2.imshow("MEAN_C", athdMEAM)
- cv2.imshow("GAUSSIAN_C", athdGAUS)
- cv2.waitKey() # 按下任何键盘按键后
- cv2.destroyAllWindows() # 销毁所有窗口
复制代码
与上述5种阈值处置惩罚方法相比:
- 自适应阈值处置惩罚:只能处置惩罚灰度图
- 自适应阈值处置惩罚:生存了图像中更多的细节信息,更明显地生存了灰度图像主题的表面
- 能更好地处置惩罚明暗分布不均的图像,获得更简单的图像效果。
- import cv2 as cv
- import matplotlib.pyplot as plt
- # 读取图像
- img=cv.imread('beauty4.jpeg')
- gray_img=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
- # 5种阈值化处理
- ret1, thresh1=cv.threshold(gray_img, 127, 255, cv.THRESH_BINARY)
- ret2, thresh2=cv.threshold(gray_img, 127, 255, cv.THRESH_BINARY_INV)
- ret3, thresh3=cv.threshold(gray_img, 127, 255, cv.THRESH_TRUNC)
- ret4, thresh4=cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO)
- ret5, thresh5=cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO_INV)
- # 自适应阈值的计算方法为cv2.ADAPTIVE_THRESH_MEAN_C
- athdMEAM = cv.adaptiveThreshold(gray_img, 255, cv.ADAPTIVE_THRESH_MEAN_C,
- cv.THRESH_BINARY, 5, 3)
- # 自适应阈值的计算方法为cv2.ADAPTIVE_THRESH_GAUSSIAN_C
- athdGAUS = cv.adaptiveThreshold(gray_img, 255,
- cv.ADAPTIVE_THRESH_GAUSSIAN_C,cv.THRESH_BINARY, 5, 3)
- # 显示结果
- titles = ['Gray Img','BINARY','BINARY_INV','TRUNC','TOZERO',\
- 'TOZERO_INV','Adaptive_Mean','Adaptive_Gaussian']
- images = [gray_img, thresh1, thresh2, thresh3,\
- thresh4, thresh5,athdMEAM,athdGAUS]
- # matplotlib 绘图:可以同时显示多个图像,而且图像显示在命令窗口上,而不是以窗口弹出的方式显
- 示
- for i in range(8):
- plt.subplot(2, 4, i+1), plt.imshow(images[i],'gray')
- plt.title(titles[i])
- plt.xticks([]),plt.yticks([])
- plt.show()
复制代码
自适应阈值处置惩罚:生存了图像中更多的细节信息,更明显地生存了灰度图像主题的表面
Otsu阈值处置惩罚
Ostu是一种阈值选择的算法,在面临色彩分布不均匀的图像时,阈值的选择就会变得很复杂。这时我们就不需要凭借经验去认为设定,而是根据Otsu算法来计算出最符合的阈值。
Ostu的思想很简单,属于暴力寻优的一种,分别计算选用不同灰度级作为阈值时的远景、背景、整体方差。当方差最大时,此时的阈值最好,即遍历所有大概的阈值,从中找到最符合的阈值。
Otsu’s Binarization是一种基于直方图的二值化方法,它需要和threshold函数配合使用。
对于图像二值化的简单阈值法,我们需要自己提供一个阈值,而大津法(OTSU)可以根据图像特性,选择最佳的阈值,故它也被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响。从大津法的原理上来讲,该方法又称作最大类间方差法,由于按照大津法求得的阈值进行图像二值化分割后,远景与背景图像的类间方差最大。
它是按图像的灰度特性,将图像分成背景和远景两部门。因方差是灰度分布均匀性的一种度量,背景和远景之间的类间方差越大,说明构成图像的两部门的差异越大,当部门远景错分为背景或部门背景错分为远景都会导致两部门差异变小。因此,使类间方差最大的分割意味着错分概率最小。
应用: 是求图像全局阈值的最佳方法,应用不言而喻,实用于大部门需要求图像全局阈值的场合。
优点: 计算简单快速,不受图像亮度和对比度的影响。
缺点: 对图像噪声敏感;只能针对单一目标分割;当目标和背景大小比例悬殊、类间方差函数大概出现双峰大概多峰,这个时间效果不好。
Otsu过程:
- 计算图像直方图;
- 设定一阈值,把直方图强度大于阈值的像素分成一组,把小于阈值的像素分成另外一组;
- 分别计算两组内的偏移数,并把偏移数相加;
- 把0~255依照次序多为阈值,重复1-3的步骤,直到得到最小偏移数,其所对应的值即为效果阈值。
代码展示
选择一张偏暗的图片来测试程序。
- import cv2 as cv
- import matplotlib.pyplot as plt
- image = cv.imread("beauty5.jpeg", cv.IMREAD_GRAYSCALE)
- ret1, dst1 = cv.threshold(image, 127, 255, cv.THRESH_BINARY) # 二值化阈值处理
- ret2, dst2 = cv.threshold(image, 0 , 255, cv.THRESH_OTSU) # Otsu方法
- dst3 = cv.adaptiveThreshold(image, 255,
- cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY, 5, 3) # 自适应阈值
- #cv.imshow("image", image)
- #cv.imshow("threshold", dst1)
- #cv.imshow("otsu", dst2)
- #cv.imshow("GAUSSIAN_C", dst3)
- titles = ['gray_orgin','Binary','Otsu','Adaptive_Gaussian']
- images = [image,dst1,dst2,dst3]
- for i in range(4):
- plt.subplot(2,2,i+1), plt.imshow(images[i],'gray')
- plt.title(titles[i])
- plt.xticks([]),plt.yticks([])
- cv.waitKey()
- cv.destroyAllWindows()
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |