像素是图画的根本元素,像素与像素之间存在着某些联系,理解像素间的根本联系是数字图画处理的基础。常见的像素间的根本联系包含:邻域、邻接、通路、连通、间隔。
1. 邻域
邻域表明了像素之间的衔接联系。
像素(x,y)的邻域,是指与像素(x,y)对应的点的调集{(x+p,y+q)} ,其中 (p,q) 为一对有意义的整数。邻域是像素(x,y)附近像素形成的区域,像素 (x,y) 也被称为中心像素。
最常用的邻域有以下几种:
-
4 邻域:关于像素(x,y),上下左右4个像素被称为 4 邻域,运用N4(p)N_4(p)表明。4 邻域的四个像素分别是:(x,y-1)、(x,y+1)、(x-1,y)、(x+1,y)。
-
D 邻域:关于像素(x, y), 其左上、右上、左下、右下的四个对角上的像素组成了 D 邻域,运用Nd(p)N_d(p)表明。D 邻域四个像素分别是:(x + 1, y + 1)、( x + 1, y – 1)、(x – 1, y + 1)、(x – 1, y – 1)。
-
8 邻域:关于像素(x,y),它的 4 邻域的点和 D 邻域的点组成了 8 邻域,运用N8(p)N_8(p)表明。那么,N8(p)=N4(p)+Nd(p)N_8(p)=N_4(p)+N_d(p)
邻域是一个很基础的概念。后续咱们对图画进行卷积操作的时分,通常是对当时像素的邻域像素进行操作的。
以一个最简略的均值滤波为例,均值滤波是关于每一个像素点, 将其设定为取其邻域窗口内的一切像素的平均值。
算术均值滤波器的公式:
g(x,y)=1m∗n∑i,j∈Sxyf(i,j)g(x,y)=frac{1}{m*n}sum_{i,jinS_{xy}}f(i,j)
其中,SxyS_{xy}表明以像素(x,y)为中心的区域,m*n 是 模板 的巨细。f(x,y) 表明原图画,g(x,y) 表明运用 SxyS_{xy} 定义的邻域中的像素所核算出的算术平均值。
这里的模板,也能够被称为核(kernels)、窗口(windows)、掩模(mask)。
下图以 3*3 的模板为例,均值滤波会对原图画的每一个像素点,核算它的邻域像素和模版矩阵的对应元素的乘积,然后加起来,作为该像素方位的值。窗口的移动是从左到右,然后从上到下顺次移动。
下面,完成一个简略的均值滤波函数
Mat meanFilter(Mat &src, int ksize = 3)
{
cv::Mat dst = src.clone();
int k0 = ksize/2;
int sum[3] = {0,0,0};
for(int i=k0;i<dst.rows-k0-1;i++)
{
for(int j=k0;j<dst.cols-k0-1;j++)
{
memset(sum,0, sizeof(sum));
for(int channel = 0; channel<3; channel++)
{
for(int m = 0;m<ksize;m++)
{
for (int n=0;n<ksize;n++)
{
sum[channel] += src.at<cv::Vec3b>(i-k0+m,j-k0+n)[channel];
}
}
dst.at<Vec3b>(i,j)[channel] = saturate_cast<uchar>((float)sum[channel] /(ksize*ksize));
}
}
}
return dst;
}
当然这个代码只是粗略地完成均值滤波,存在着许多优化的空间,例如运用积分图、卷积核别离等。OpenCV 也提供了均值滤波函数 blur() 函数。
int main(int argc,char *argv[])
{
Mat src = imread(".../flower.jpg");
imshow("src",src);
Mat dst;
dst = meanFilter(src, 15);
imshow("meanFilter",dst);
blur(src,dst,Size(15,15));
imshow("blur",dst);
waitKey(0);
return 0;
}
上面只是简略例举了范畴的运用场景,后续会有专门的文章来详细介绍卷积和滤波。
2. 邻接
邻接是指两个像素,在方位上相邻而且取值相同或相近。
咱们用 V 表明定义邻接的灰度值调集。在二值图画中,V={1} 表明值为1的像素邻接。在灰度图画中,V 包含更多的元素。
-
**4 邻接:**关于灰度值在 V 调集中的像素 p 和 q,假如 q 在 N4(p)N_4(p) 中,那么像素 p 和 q 是 4 邻接的。
-
**8 邻接:**关于灰度值在 V 调集中的像素 p 和 q,假如 q 在 N8(p)N_8(p) 中,那么像素 p 和 q 是 8 邻接的。
-
**m 邻接(混合邻接):**m 邻接是 8 邻接的改进。只需满足以下任何一个条件即可:
-
q 在 N4(p)N_4(p) 中
-
q 在 Nd(p)N_d(p) 中,且调集在 N4(p)∩N4(q)N_4(p)cap N_4(q) 中没有来自 V 中的像素。
-
像素 p 和 q 是 4 邻接,那么它们一定是 8 邻接的。反之,不一定成立。
下图反响了 8 邻接会带来二义性。
从图中能够看到,p 是中心像素。
-
q1、q2 和 p 是 8 邻接的。
-
q1 和 p 非 m 邻接的。
-
q2 和 p 是 m 邻接的。
某条通路通过像素 q2、p、q1,那会有几种走法呢?
假如从 p、q1、q2 是 8 邻接的视点看,p 到 q1 能够有2种走法,所以 q2 到 q1 的通路有2条。
同理,从 m 邻接视点看,p 和 q1 只有1种走法,所以 q2 到 q1 的通路只有1条。
所以,m 邻接的引进是为了消除 8 邻接常常带来二义性。
从调集的视点看:4邻接⊂m邻接⊂8邻接4 邻接subsetm 邻接subset8邻接
3. 通路
通路:从像素 p(x0,y0)(x_0,y_0) 到像素 q(xn,yn)(x_n,y_n) 的通路是特定的像素序列,其坐标为:
(x0,y0),(x1,y1),(x2,y2),…(xn,yn)(x_0,y_0),(x_1,y_1),(x_2,y_2),…(x_n,y_n)
而且满足, (xi,yi)(x_i,y_i) 和 (xi−1,yi−1)(x_{i-1},y_{i-1}) 关于 1≤i≤n1leqileqn 是邻接的。
**闭合通路:**假如满足(x0,y0)=(xn,yn)(x_0,y_0)=(x_n,y_n),则通路是闭合通路。
由不同的邻接定义,能够得到不同的通路:4 邻接 => 4 通路,8 邻接 => 8 通路,m 邻接 => m 通路
所以,从中心的图能够看到 q2 和 q1 之间存在 8 通路,从最右的图能够看到 q2 和 q1 之间存在 m 通路。
从调集的视点看:4通路⊂m通路⊂8通路4通路subsetm 通路subset8通路
下图中,p-q 通路对应的是不同的通路。
4. 连通
连通:若 S 是图画中的一个像素子集,关于恣意的 p、q∈Sp、qinS。假如存在一条由 S 中像素组成的从 p 到 q 的通路,则称 p 在图画集 S 中与 q 连通。
邻接是连通的一种特例,连通是由一系列顺次邻接的像素组成的。
连通分为 4 连通和 8 连通。
连通重量:关于 S 中恣意像素 p,一切与 p 相连通且又在 S 中的像素调集。
连通集:假如 S 中仅有一个连通重量,则 S 称为连通集。
在之前根本图形的绘制那篇文章里, 曾介绍过绘图函数所运用的 lineType 参数。
下面对这个参数做一些弥补阐明:
-
LINE_4 :根据 4 连通 Bresenham 算法处理的直线。
-
LINE_8 :根据 8 连通 Bresenham 算法处理的直线。
-
LINE_AA :根据高斯滤波滑润处理的直线。
下面的例子,展示了运用不同的 lineType 参数的作用
int main(int argc,char *argv[])
{
Mat image = Mat::zeros(Size(80, 80), CV_8UC3);
image.setTo(255);// 设置屏幕为白色
Point p1(20, 0);
Point p2(80, 60);
Point p3(0, 0);
Point p4(80, 80);
Point p5(0, 20);
Point p6(60, 80);
line(image, p1, p2, Scalar(0, 0, 255), 1, LINE_4);
line(image, p3, p4, Scalar(255, 0, 0), 1, LINE_8);
line(image, p5, p6, Scalar(0, 255, 0), 1, LINE_AA);
imshow("src", image);
waitKey(0);
return 0;
}
将生成的图片扩大,能够看到运用 LINE_4、LINE_8、LINE_AA 画出来的线段作用是不同的。运用 LINE_AA 作用看上去是最好的,其次是 LINE_8。
通过邻接能够引申许多概念,邻接 -> 通路 -> 连通 -> 连通集 -> 区域/邻接区域 -> 远景和背景 -> 鸿沟
5. 间隔
关于像素 p(x,y)、q(s,t) 和 z(u,v),假如满足:
-
非负性:D(p,q) ≥ 0
-
同一性:D(p,q)=0,当且仅当p=q时
-
对称性:D(p,q) = D(q,p)
-
直递性:D(p,z) ≤ D(p,q) + D(q,z)
则称 D 是间隔的衡量函数。
在欧几里得空间中,点(x1,x2,…,xn)(x_1,x_2,…,x_n)和点(y1,y2,…,yn)(y_1,y_2,…,y_n)之间的闵可夫斯基间隔:
D(x,y)=(∑i=1n∣xi−yi∣p)1/pD(x,y)=(sum_{i=1}^{n}|x_i – y_i|^p)^{1/p}
- 曼哈顿间隔
当 p = 1 时,即为曼哈顿间隔或城市间隔、街区间隔,是指两个向量之间的间隔,在核算间隔时不触及对角线移动。像素 p(x,y) 和 q(s,t) 之间的间隔公式:
D4(p,q)=∣x−s∣+∣y−t∣D_4(p,q)=|x-s|+|y-t|
表明从像素 p 向像素 q 动身,每次能走的点必须是在当时像素点的 4 邻域中。一步一步走到 q 点后,总共通过的像素点数便是曼哈顿间隔。
- 欧式间隔
当 p = 2 时,即为欧式间隔,便是直角坐标系的间隔。像素 p(x,y) 和 q(s,t) 之间的间隔公式:
De(p,q)=(x−s)2+(y−t)2D_e(p,q)=sqrt{(x-s)^2+(y-t)^2}
- 切比雪夫间隔
当 p = ∞infty 时,即为切比雪夫间隔或棋盘间隔,像素 p(x,y) 和 q(s,t) 之间的间隔公式:
D8(x,y)=max(∣x−s∣,∣y−t∣)D_8(x,y)=max(|x-s|,|y-t|)
表明从像素 p 向像素 q 动身,每次能走的点必须是在当时像素点的 8 邻域中。一步一步走到 q 点后,总共通过的像素点数便是切比雪夫间隔。
6. 总结
本文触及到许多概念,这些概念代表着像素间的根本联系。像邻域、连通在后续文章中许多都会触及到,像间隔又跟类似度有关,所以它们是数字图画的基础。