基于python-tensorflow的机器视觉学习手札 (1.3)图像处理篇-图像类型转换、二值化、灰度增强

首先补一下忘记说了的最基础的东西 二值化 之类的基础操作

0 图像之间转换

0.1各种类型的相互转换

图像类型转换通常是在索引色、灰度图、真彩色(RGB)、二值图像之间。matlab中,有函数分别对应各种类型的相互转换:
dither抖动法把灰度变成二值图,或把真彩色抖动成索引色
gray2ind将灰度图转换为索引图
grayslice通过设定阈值,将灰度图转换为索引图
im2bw通过设定阈值,将各种图转换为二值化图
ind2gray索引转灰度 ind2rgb 索引转真彩
rgb2gray真彩转灰度 rgb2ind 真彩转索引

在具体的操作中,索引色除了一些展示数据的场合,很少以图像的形式显示。而灰度图,真彩色的各个通道,二值图,都有各自特殊的作用,在对象检测、模式识别等领域被广泛的使用。
在python中,也同样可以用opencv来实现由真彩色转换为灰度图,与灰度图二值化,并且二值化有很多方式。
由真彩色变为灰度图我们可以用:

im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

0.2 二值化

二值化是大多数图像处理中很重要的一个环节,它可以使图像变得更简单。为了使二值化的效果更好,二值化的方法也在不断进步。

0.2.1 固定阈值二值化

开始是固定阈值的二值化,就是大于n的只设为255,小于n的值设为0,这个n就是全局固定阈值。这种方法会出现在不同的明暗环境下,目标和背景不能够很好的被区分。
在matlab中,可以用graythresh自动获取阈值,再用im2bw来做二值化操作。并且这种操作并不需要图像先转换为灰度图,直接真彩色也可以二值化。
在python中,固定阈值的二值化操作如下:

retval, im_at_fixed= cv2.threshold(im_gray, 50, 255, cv2.THRESH_BINARY) 
#将阈值设置为50,阈值类型为cv2.THRESH_BINARY,则灰度在大于50的像素其值将设置为255,其它像素设置为0
cv2.axis("off") 
cv2.title("Fixed Thresholding")
cv2.imshow(im_at_fixed, cmap = 'gray') 
cv2.show()

#附:固定阈值二值化处理利用cv2.threshold函数,此函数的原型为:
cv2.threshold(src, thresh, maxval, type[, dst]) -> retval, dst
其中:
1、src 为输入图像;
2、thresh 为阈值;
3、maxval 为输出图像的最大值;
4type 为阈值的类型;
5、dst 为目标图像。

#附cv2.threshold函数的常用参数
1、cv2.THRESH_BINARY(黑白二值) 
2、cv2.THRESH_BINARY_INV(黑白二值反转) 
3、cv2.THRESH_TRUNC (低于阈值置0,其他重新分散在255-04、cv2.THRESH_TOZERO (高于阈值置2555、cv2.THRESH_TOZERO_INV (低于阈值置255,其他重新分散在255-0

实际试运行:

import cv2 
im = cv2.imread('timg.jpg')
im_gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY)
retval, im_at_fixed = cv2.threshold(im_gray, 70, 255, cv2.THRESH_BINARY) 
#将阈值设置为70,阈值类型为cv2.THRESH_BINARY,则灰度在大于50的像素其值将设置为255,其它像素设置为0
cv2.namedWindow("image")
cv2.imshow('image', im_at_fixed)
cv2.waitKey (0) 
cv2.destroyAllWindows()

0.2.2 自适应阈值二值化

前面也说了,这种方法,在图片明暗不均匀的情况下很容易不能识别出感兴趣的部分。因此,出现了自适应阈值二值化的方法:

dst = cv2.adaptiveThreshold(src, maxval, thresh_type, type, Block Size, C)
#src: 输入图,只能输入单通道图像,通常来说为灰度图
#dst: 输出图
#maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
#thresh_type: 阈值的计算方法,包含以下2种类型:cv2.ADAPTIVE_THRESH_MEAN_C; cv2.ADAPTIVE_THRESH_GAUSSIAN_C.
#type:二值化操作的类型,与固定阈值函数相同,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV.
#Block Size: 图片中分块的大小
#C :阈值计算方法中的常数项,从均值中减去,得到阈值;

实验代码如下:

# -*- coding: utf-8 -*-
"""
Created on Mon Aug  6 16:57:39 2018

@author: Administrator
"""
import cv2 
im = cv2.imread('timg.jpg')
im_gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY)
im_at_fixed = cv2.adaptiveThreshold(im_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY, 11, 2)
cv2.namedWindow("image")
cv2.imshow('image', im_at_fixed)
cv2.waitKey (0) 
cv2.destroyAllWindows()

这种方法已经可以较好的实现二值化了。然而还有一种方法,需要结合直方图来使用,它就是Otsu’s Binarization。这种方法对应双峰图片(背景与目标区别较大,切分的比较开)非常有效。由于需要结合直方图使用,那这种方法放在直方图后面说吧(快了)。

1 图像增强技术

ok进入今天的正题,也就是图像增强技术。图像增强技术多种多样,可以在空域,也可以在频域,是图像处理中较为核心的部分。

1.1 空域上的图像增强

1.1.1 灰度图增强

首先说灰度图的增强,如果一幅灰度图像素值差距过小,那么就会出现对比度低,不清晰的情况,这时就需要增强技术来提高对比度,使图像清晰一些(感官上)。
观测一幅灰度图的像素值分布,那就需要用到直方图。在matlab中,可以运用函数imhist来获取到图像的直方图。 在获得直方图后,就可以判断出像素值大多分布在哪一个范围内,再用imadjust来进行图像的灰度调整,同时也可以对gamma值进行调整。彩色图像也是同样,对rgb图像的各个通道进行调整。
调整亮度除了这种方法,还有一种方法是用brighten来调整,不过这个只能调整figure中的图像,对矩阵没有影响。
在用imadjust进行图像调整时,可以通过函数strechlim来计算图像的最佳输入区间,这样就不需要手动判断像素值分布范围。
此外,还有函数imcomplement,作用是进行灰度的反转变换,黑白互换。主要目的是可以让人注意到暗色背景下的白色或灰色的细节信息。

既然我们得到了直方图,那就可以做直方图均衡化了。直方图均衡化是一种利用灰度变换自动调节图像对比度质量的方法,不仅与图像像素值分布范围有关,同样也和概率有关。在matlab中提供了函数histeq进行直方图均衡化。直方图均衡化之后,可以看到更多的细节信息,经过处理之后直方图的分布更加均匀。
histeq还可以用来做直方图规定化,可以把直方图部分灰度级进行增强,来突出用户感兴趣部分灰度值的细节。
用直方图进行增强有几点不足,一是灰度级有所减少,会使特别小的细节消失;二是当直方图有高峰的时候,处理后容易产生不自然的过分增强,达不到增强图像的效果。
python-opencv中,直方图均衡化可以用函数equalizeHist来实现,具体实验程序如下:

import numpy as np
import cv2 

im= cv2.imread('timg.jpg')
im_gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY)
equ = cv2.equalizeHist(im_gray)
res = np.hstack((im_gray, equ)) # 并排叠加图片
cv2.namedWindow("image")
cv2.imshow('image', res)
cv2.waitKey (0) 
cv2.destroyAllWindows()

至于对比度和亮度的变化,目前看到更多的都是自己写映射来实现,用numpy实现会简单一些,如:

import numpy as np
import cv2 
img = cv2.imread('timg.jpg')
im_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
res = np.uint8(np.clip((1.5 * im_gray + 10), 0, 255))
tmp = np.hstack((im_gray, res)) 
cv2.namedWindow("image")
cv2.imshow('image', tmp)
cv2.waitKey (0) 
cv2.destroyAllWindows()

补充一下大津法OTSU:
大津法就是最大类间方差法,这种方法把图像根据阈值区分成两个图像,分别是背景与目标(又叫前景与背景),使两幅图像方差最大对于直方图有双峰值(背景和目标)的图像特别好用,能很容易的区分背景与目标。不过大津法对噪音和目标大小十分敏感,它仅对类间方差为单峰的图像产生较好的分割效果。

import cv2
img = cv2.imread("timg.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
retval, dst = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)
cv2.imshow("dst", dst)
cv2.waitKey(0)

还是使用threshold来实现,不过后面的value设为cv2.THRESH_OTSU,这样会自动计算大津法得到的阈值。
下篇总结一下简单的空域滤波和频域滤波吧!先溜了溜了
请多多指教,谢谢!

你可能感兴趣的:(心得体会)