图像基础操作
本文介绍图像处理中的一些基本概念,包括图像增强、图像增广、边缘提取等。本文的代码使用OpenCV的python接口,及Numpy。
基础操作
随机生成像素
rows=200
cols=300
num=2000 #随机像素点的个数
img=np.zeros((rows,cols,3),np.unit8)
pos1=np.random.randint(200,size=(num,1)) #行位置随机数组
pos2=np.random.randint(300,size=(num,1)) #列
#随机位置处设置像素点值
for i in range(num):
img[pos1[i],pos2[i],[0]]=np.random.randint(0,255)
img[pos1[i],pos2[i],[1]]=np.random.randint(0,255)
img[pos1[i],pos2[i],[2]]=np.random.randint(0,255)
如果在OpenCV中处理图像,是BGR的顺序。
调节图像亮度
将每个像素的RGB值变小则亮度调小,变暗;将值变大则变亮。
日落效果
将蓝色与绿色值设为原来的70%
负片
反色,将像素的三色值设为(255-原值)
水印
cv2.putText(img,"xxxtext",(pos_x,pos_y),cv2.FONT_HERSHEY_PLAIN,2.0,(0,0,0),thickness=2)
旋转、平铺、镜像
旋转一定的角度比较麻烦一些,平铺、镜像简单
图像融合
将两个图像对应元素相加取平均。
减均值
从图像中减去均值有助于在不同光照条件下对图像进行归一化。一般代码为:
image = image - image.mean()
二值化
将图像进行二值化可以呈现明显的黑白视觉效果。比较简单的方法是卡阈值:对于每一个像素,大于阈值的设为1,其它设为0,将图像转换为二值图像,可以用于选择感兴趣的区域。其中一种选择阈值的方法叫Otsu,需要先把图像转换为灰度图。此外还有Ridley-Calvard方法等。
OpenCV的threshold方法:retval,dst = cv2.threshold(src,thresh,maxval,type)
用来简单地卡阈值,adaptiveThreshold
方法可以自适应二值化,参数blockSize决定局部阈值的block大小,其值较小时可以提取边缘。
灰度化
灰度图像是一种具有从黑到白256级灰度色阶或等级的单色图像,每个像素均用8位数据表示。图像只有灰度等级,没有颜色的变化。值越大,显示效果越亮。
两种方式:
- 求出每个像素点的RGB三个分量的平均值,然后将此值赋予三个分量。(结果图仍是24bit深度)
- 根据RGB与YUV颜色空间的变化关系,建立亮度Y与RGB三个颜色通道的对应关系:Y=0.3R+0.59G+0.11B,以这个亮度值表达图像的灰度值。(8bit深度)
img2 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
灰度变换与图像增强
灰度变换
将每一个像素的灰度值按照一定的数学变换公式转换成一个新的灰度值,以此来增强图像,扩展图像的对比度,使图像变清晰,使其特征更加突出
变换方式
- 对数变换(低亮度区更清晰)
- 分段线性变换(通过压缩高亮度区,扩展低亮度区使图像的对比度增加)
- 指数变换(突出显示高亮度区,使亮的更亮)
- 直方图均衡化
通过统计灰度值的直方图数据,再转成累加概率函数,再映射到原来值的范围之内。这样使得原本相近的灰度值差值变大,像素间的对比度增大。这样增加了全局对比度,尤其使局部的对比更明显。
OpenCV中有cv2.equalizeHist(srcImg) -> dstImg
可直接使用。
彩色图像直方图均衡化
OpenCV 可以对灰度图进行equalizeHist(graySrc, dst)
;
我们也可以对彩色图像做直方图均衡化.
- 方法一. 对RGB三通道各自均衡化后,再组合输出结果.
- 方法二. 将RGB图像转化为HSI/YUV/YCbCr等颜色空间后,对亮度通道进行均衡化运算后再转回RGB空间.
C++ 代码实现。
方法一:各个通道分别均衡化:
vector<Mat> channels;
split(inputImage, channels);
Mat B,G,R;
equalizeHist( channels[0], B );
equalizeHist( channels[1], G );
equalizeHist( channels[2], R );
vector<Mat> combined;
combined.push_back(B);
combined.push_back(G);
combined.push_back(R);
Mat result;
merge(combined, result);
方法二: 亮度均衡化
Mat ycrcb;
cvtColor(inputImage, ycrcb, COLOR_BGR2YCrCb);
vector<Mat> channels;
split(ycrcb, channels);
equalizeHist(channels[0], channels[0]);
Mat result;
merge(channels,ycrcb);
cvtColor(ycrcb, result, COLOR_YCrCb2BGR);
RGB各通道均衡化后图像颜色有失真情况,而亮度通道均衡化结果不会.均衡化是针对亮度的而不是针对颜色的.推荐使用YCbCr颜色空间对亮度进行均衡化,因为该颜色空间是为数码图片设计的.
图像噪声
图像加噪(椒盐噪声)
修改若干像素点的值为某一像素值。生成单个随机位置的代码:
xi=int(np.random.uniform(0,img.shape[1]))
xj=int(np.random.uniform(0,img.shape[0]))
if img.ndim == 2: #gray dim
img[xj,xi]=255
elif img.ndim == 3:
img[xj,xi,:]=[B,G,R]
图像加噪的目的
:为了试验图像识别的效果,测试机器学习算法的能力。
pepper代指几乎为黑色的值,如30;salt代指几乎为白色的值,如170.
图像滤波与去燥
均一化块
核函数 K =
OpenCV 的 blur
函数可以进行归一化块滤波操作。
领域平均法
核:
半径为1:$$\frac{1}{4}
\left[
\begin{matrix}
0 & 1 & 0 \
1 & 0 & 1 \
0 & 1 & 0
\end{matrix}
\right] \tag{1}
中值滤波
与领域平均法的区别为计算的是中值而不是平均值。
高斯滤波(高斯模糊)
对整幅图像中的每个像素计算领域内像素的加权平均值,权值即卷积核(或称模板)。
OpenCV 有 GaussianBlur
函数。滤波器大小(标准差)越大,图片结果越模糊。通过模糊化,把和总体布局无关的细节都去掉了。常用于降噪,可以对后续的处理有所帮助。
聚焦中心:使用高斯模糊进行模糊化,再用高斯函数赋予中心区域一个高权重。可以图像边缘较为柔和,焦点集中于中央区域。
双边滤波
cv2.bilateralFilter
是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折中处理方法,同时考虑空域信息和灰度相似性,达到保边去噪的目的。
卷积滤波
对每一个像素,以其为中心的卷积核大小的矩阵与卷积核对应元素相乘再累加求和,和上边的方法很相似。
gabor 滤波 [1][2]
gabor filter是经典的带通滤波器之一,可以用来提取图像边缘.(深度学习的相关论文有些以自己的模型能够学习出类似 gabor filter 的参数为荣).
在图像处理领域,以Dennis Gabor命名的Gabor滤波器,是一种用于纹理分析的线性滤波器,即它主要分析的是,图像在某一特定区域的特定方向上是否有特定的频率内容。当代许多视觉科学家认为,Gabor滤波器的频率和方向的表达与人类的视觉系统很相似,尽管并没有实验性证据和函数原理能证明这一观点。研究发现,Gabor滤波器特别适合于纹理表示和辨别。在空间域中,2D Gabor滤波器是由正弦平面波调制的高斯核函数。
滤波与边缘检测
- Laplacian边缘检测使用了Sobel算子
- sobel非线性滤波,采用梯度的模的计算方式提取边缘,锐化图像。(可以将颜色反转,255-原值,以便更好地看出边缘效果。)
- gabor 滤波可以用来提取图像边缘。
图像边缘勾勒:将当前像素与邻接的下部和右部的像素进行比较,如果相似,则将当前像素设置为黑色,否则设置为白色。(也可以为中间值设置一些中间色)。
图像导数
图像中的强度变化情况通常可以作为重要的信息,强度的变化可以用灰度图像I(对于彩色图像,通常对每个颜色通道分别计算导数)的x和y方向导数\(I_x,I_y\)进行描述。
梯度向量为\(\nabla I=[I_x,I_y]^T\)。
梯度有两个重要的属性,
一是梯度大小,描述了图像强度变化的强弱:
一是梯度的角度,描述了图像在每个像素点上强度变化最大的方向。
近似计算
图像导数大多可以通过卷积来简单地计算离散近似值:
通常选择Prewitt滤波器:
或Sobel滤波器:
这些导数滤波器可以使用scipy.ndimage.filters
模块的标准卷积操作来简单实现。
上述方法的缺陷
滤波器的尺度需要随着图像分辨率的变化而变化。
为了在图像噪声方面更稳健,以及在任意尺度上计算导数,我们可以使用高斯导数滤波器。filters.gaussian_filter()
模式识别
由于历史的原因,图像分类又叫做模式识别。
模式识别通常包括分解、特征提取、分类几个过程。分解的内容可能是图像、数据,这个分解过程实现自动化是较难的,分解后形成分区、有限的内容子集。特征提取分析不同类的不同的特征,需要对分解后的内容进行各种数学分析。分类基于特征分析来进行。
模式识别难点
- 视角不同viewpoint variation
- 尺寸大小不一scale variation
- 变形deformation
- 光影等干扰occlusion/illumination conditions
- 背景干扰background clutter
- 同类物体的差异intra-class variation
图像匹配
判断图片A是否是图片B的子图。
- 差分矩阵
差分矩阵 = 图像A矩阵 - 图像B矩阵
若差分矩阵每个元素的和或矩阵均值小于某一阈值,则认为匹配。 - 欧式距离
对于强噪声环境下以及旋转的图像进行匹配时,欧式距离匹配方法相对于查分矩阵会有更好的效果。
def getEuclideanDist(x,y):
ax=np.array(x)
ay=np.array(y)
return np.sqrt(np.sum((ax-ay)*(ax-ay)))
图像增广
图像数据扩增(data augmentation):
- 水平翻转(Horizontal flipping) (垂直翻转根据视角是否有上下颠倒的需求而定)
- 随机裁剪(Random cropping)
- 随机放缩(Random scaling)
- 颜色抖动(Color jittering)
- 随机平移(Random translation)
- 随机剪切(Random shearing)
较常用的有水平翻转, 随机裁剪和颜色抖动. 并且可以组合多种方式. 可以改变saturation 和 value (HSV 颜色空间的S和V组件) 的值等方式.
图像聚类
聚类可以用于识别、划分图像数据集,组织与导航。此后可以对聚类后的图像进行相似性可视化。