机器视觉重点
数字图像的概念与性质
距离
距离种类
- 欧氏距离:%5E2%2B(n-k)%5E2%7D#card=math&code=D_E%3D%5Csqrt%7B%28m-h%29%5E2%2B%28n-k%29%5E2%7D&id=vyDbE)
- 城区距离:
- 棋盘距离:
距离变换
给出图像中每个像素与某个图像子集的距离,算法如下:
- 从上到下,从左至右遍历,%3D%5Cunderset%7Bq%5Cin%20AL%7D%7B%5Cmin%7D%5C%7BF(p)%2CD(p%2Cq)%2BF(q)%5C%7D#card=math&code=F%28p%29%3D%5Cunderset%7Bq%5Cin%20AL%7D%7B%5Cmin%7D%5C%7BF%28p%29%2CD%28p%2Cq%29%2BF%28q%29%5C%7D&id=UcbBV)
- 从下到上,从右到左遍历,%3D%5Cunderset%7Bq%5Cin%20BR%7D%7B%5Cmin%7D%5C%7BF(p)%2CD(p%2Cq)%2BF(q)%5C%7D#card=math&code=F%28p%29%3D%5Cunderset%7Bq%5Cin%20BR%7D%7B%5Cmin%7D%5C%7BF%28p%29%2CD%28p%2Cq%29%2BF%28q%29%5C%7D&id=EXqGL)
import numpy as np def distanceTransform(img): # 默认传入参数为二值图,子集为0,其余为无穷大(255) result = img.copy() rows, cols = result.shape AL = np.array([[-1, 0], [-1, -1], [0, -1], [1, -1]]) BR = np.array([[1, 0], [1, 1], [0, 1], [-1, 1]]) for col in range(cols): for row in range(rows): for next in AL: [next_row, next_col] = [row, col] + next if 0 <= next_row < rows and 0 <= next_col < cols: if result[next_row, next_col]+abs(row-next_row)+abs(col-next_col) < result[row, col]: result[row, col] = result[next_row, next_col]+abs(row-next_row)+abs(col-next_col) for col in range(cols-1, -1, -1): for row in range(rows-1, -1, -1): for next in BR: [next_row, next_col] = [row, col] + next if 0 <= next_row < rows and 0 <= next_col < cols: if result[next_row, next_col]+abs(row-next_row)+abs(col-next_col) < result[row, col]: result[row, col] = result[next_row, next_col]+abs(row-next_row)+abs(col-next_col) return result
边缘与边界
- 边缘:像素与其直接邻接的局部性质,是图像上亮度的不连续点,是矢量。方向与梯度垂直,大小与梯度相等。
- 边界是与区域有关的全局概念
噪声
- 加性噪声:噪声与图像信号无关
- 乘性噪声:噪声幅值与信号本身幅值有关
卷积
- 卷积定义:
%26%3Df(x%2Cy)*h(x%2Cy)%5C%5C%0A%26%3D%5Cint%7B-%5Cinfty%7D%5E%7B%5Cinfty%7D%5Cint%7B-%5Cinfty%7D%5E%7B%5Cinfty%7Df(x-a%2Cy-b)h(a%2Cb)dadb%0A%5Cend%7Baligned%7D%0A#card=math&code=%5Cbegin%7Baligned%7D%0Ag%28x%2Cy%29%26%3Df%28x%2Cy%29%2Ah%28x%2Cy%29%5C%5C%0A%26%3D%5Cint%7B-%5Cinfty%7D%5E%7B%5Cinfty%7D%5Cint%7B-%5Cinfty%7D%5E%7B%5Cinfty%7Df%28x-a%2Cy-b%29h%28a%2Cb%29dadb%0A%5Cend%7Baligned%7D%0A&id=jsFYg)
- 若系统响应可以表示成卷积的形式,则该系统是一个线性移不变系统;
任意线性移不变系统可以表示成卷积形式 - 离散卷积:
%26%3D%5Csum%7Bk%3D0%7D%5E%7BM_2-1%7D%5Csum%7Bl%3D0%7D%5E%7BN2-1%7Df(m-k%2Cn-l)h(k%2Cl)%5C%5C%0A%26%3D%5Csum%7Bk%3D0%7D%5E%7BM1-1%7D%5Csum%7Bl%3D0%7D%5E%7BN1-1%7Df(k%2Cl)h(m-k%2Cn-l)%0A%5Cend%7Baligned%7D%0A#card=math&code=%5Cbegin%7Baligned%7D%0Ag%28m%2Cn%29%26%3D%5Csum%7Bk%3D0%7D%5E%7BM2-1%7D%5Csum%7Bl%3D0%7D%5E%7BN2-1%7Df%28m-k%2Cn-l%29h%28k%2Cl%29%5C%5C%0A%26%3D%5Csum%7Bk%3D0%7D%5E%7BM1-1%7D%5Csum%7Bl%3D0%7D%5E%7BN_1-1%7Df%28k%2Cl%29h%28m-k%2Cn-l%29%0A%5Cend%7Baligned%7D%0A&id=pWSwW)
其中#card=math&code=f%28x%2Cy%29&id=BsDk9)尺寸是,#card=math&code=h%28x%2Cy%29&id=RbQYF)尺寸是
卷积后尺寸为高为,宽为
图像预处理
像素亮度变换
- 亮度校正:与像素位置相关
- 灰度级变换:与像素位置无关,将原来在范围内的亮度p变换为内的亮度#card=math&code=q%3DT%28p%29&id=yl0fP)。
典型灰度级变换方法:
- 底片变换
- 分段增强
- 图像二值化
- 直方图均衡化:创建一副在整个亮度范围内有相同亮度分布的图像,增强靠近直方图极大值附近的亮度对比度,减小了极小值附近的对比度。
ds%3D%5Cint%7Bq_0%7D%5Eq%5Cfrac%7BMN%7D%7Bq_k-q_0%7Dds%3D%5Cfrac%7BMN(q-q_0)%7D%7Bq_k-q_0%7D%5C%5C%0Aq%3D%5Cfrac%7Bq_k-q_0%7D%7BMN%7D%5Cint%7Bp0%7D%5EpH(s)ds%2Bq_0%5C%5C%0Aq%3D%5Cfrac%7Bq_k-q_0%7D%7BMN%7D%5Csum%7Bs%3Dp0%7D%5EpH(s)%2Bq_0%0A#card=math&code=%5Cint%7Bp0%7D%5EpH%28s%29ds%3D%5Cint%7Bq0%7D%5Eq%5Cfrac%7BMN%7D%7Bq_k-q_0%7Dds%3D%5Cfrac%7BMN%28q-q_0%29%7D%7Bq_k-q_0%7D%5C%5C%0Aq%3D%5Cfrac%7Bq_k-q_0%7D%7BMN%7D%5Cint%7Bp0%7D%5EpH%28s%29ds%2Bq_0%5C%5C%0Aq%3D%5Cfrac%7Bq_k-q_0%7D%7BMN%7D%5Csum%7Bs%3Dp_0%7D%5EpH%28s%29%2Bq_0%0A&id=bJApN)
在实际应用中一般固定为,则
%0A#card=math&code=q%3D%5Cfrac%7B255%7D%7BMN%7D%5Csum_%7Bs%3D0%7D%5EpH%28s%29%0A&id=MFgQK)
def hist_equal(img_, z_max=255):
img = img_.astype(np.float)
H, W, C = img.shape
S = H * W * C * 1.
out = img.copy()
sum_h = 0.
for i in range(0, 256):
ind = np.where(img == i) # 找到对应像素所在的坐标
sum_h += len(img[ind])
z_prime = z_max / S * sum_h
out[ind] = z_prime
out = out.astype(np.uint8)
return out
几何变换
图像坐标变换
- 双线性变换(需要四个对应点对)
- 仿射变换(需要三个对应点对)
亮度插值
确定对应于输出图像离散栅格点在输入图像中点,对输入图像进行亮度插值
- 利用插值核对原图像进行卷积运算
- 最近邻插值:%3Df(round(x)%2Cround(y))#card=math&code=f%27%28x%2Cy%29%3Df%28round%28x%29%2Cround%28y%29%29&id=cnlQH)
- 亮度插值:考虑四个相邻点,假设亮度线性。减轻最近邻插值中出现的阶梯状直边界
- 双三次插值:考虑16个相邻点,解决了阶梯状边缘问题和模糊问题,较好地保持了图像细节
局部预处理
线性滤波
- 均值滤波:多次采集相同静态景物获得平均图像,噪声均值为0,标准差为。如果就一张,则局部邻域平均滤波。
- 高斯滤波:基于高斯函数形成卷积核,便于去除服从正态分布的噪声
非线性滤波
仅使用邻域中与被处理像素有类似性质的点进行平滑
- 设定非法数据范围,只有在该范围内的像素值会被有效邻域的平均替代。掩膜为:
%3D%5Cleft%5C%7B%0A%20%20%5Cbegin%7Baligned%7D%0A%20%20%261%5Cquad%20f(m%2Bi%2Cn%2Bj)%5Cnot%5Cin%5B%5Cmin%2C%5Cmax%5D%5C%5C%0A%20%20%260%5Cquad%20other%0A%20%20%5Cend%7Baligned%7D%0A%5Cright.%0A%5Cend%7Baligned%7D%0A#card=math&code=%5Cbegin%7Baligned%7D%0Ah%28i%2Cj%29%3D%5Cleft%5C%7B%0A%20%20%5Cbegin%7Baligned%7D%0A%20%20%261%5Cquad%20f%28m%2Bi%2Cn%2Bj%29%5Cnot%5Cin%5B%5Cmin%2C%5Cmax%5D%5C%5C%0A%20%20%260%5Cquad%20other%0A%20%20%5Cend%7Baligned%7D%0A%5Cright.%0A%5Cend%7Baligned%7D%0A&id=nxfsw)
- 根据反梯度的平均
%3D%5Cfrac%7B1%7D%7B%7Cf(m%2Cn)-f(i%2Cj)%7C%7D%0A#card=math&code=%5Cdelta%28i%2Cj%29%3D%5Cfrac%7B1%7D%7B%7Cf%28m%2Cn%29-f%28i%2Cj%29%7C%7D%0A&id=D31Ae)
其中如果%3Df(i%2Cj)#card=math&code=f%28m%2Cn%29%3Df%28i%2Cj%29&id=UXOYW)则%3D2#card=math&code=%5Cdelta%28i%2Cj%29%3D2&id=Gx78C);#card=math&code=%28m%2Cn%29&id=K0wv9)为掩膜中心
加权系数:
%7D%7B%5Csum%5Cdelta(i%2Cj)%7D%5Cquad%20%E9%9D%9E%E6%8E%A9%E8%86%9C%E4%B8%AD%E5%BF%83%0A%20%20%20%20%5Cend%7Baligned%7D%0A%5Cright.%0A%5Cend%7Baligned%7D%0A#card=math&code=%5Cbegin%7Baligned%7D%0A%5Cdelta%3D%5Cleft%5C%7B%0A%20%20%20%20%5Cbegin%7Baligned%7D%0A%20%20%20%20%260.5%20%5Cquad%20%E6%8E%A9%E8%86%9C%E4%B8%AD%E5%BF%83%5C%5C%0A%20%20%20%20%260.5%5Cfrac%7B%5Cdelta%28i%2Cj%29%7D%7B%5Csum%5Cdelta%28i%2Cj%29%7D%5Cquad%20%E9%9D%9E%E6%8E%A9%E8%86%9C%E4%B8%AD%E5%BF%83%0A%20%20%20%20%5Cend%7Baligned%7D%0A%5Cright.%0A%5Cend%7Baligned%7D%0A&id=SYGCs)
区域像素比边缘像素权重更大
- 旋转掩膜平均
计算该像素点在不同掩膜中的方差:
%5Cin%20h%7D%5Bf(i%2Cj)-%5Cfrac%7B1%7D%7Bn%7D%5Csum%7B(i%2Cj)%5Cin%20h%7Df(i%2Cj)%5D%5E2%5C%7D%0A#card=math&code=%5Csigma%5E2%3D%5Cfrac%7B1%7D%7Bn%7D%5C%7B%5Csum%7B%28i%2Cj%29%5Cin%20h%7D%5Bf%28i%2Cj%29-%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7B%28i%2Cj%29%5Cin%20h%7Df%28i%2Cj%29%5D%5E2%5C%7D%0A&id=dhvYp)
选择方差最小的掩膜,其均值即为该像素点最终结果
- 中值滤波:用像素邻域灰度值的中值代替该像素的灰度值,便于去除脉冲噪声、椒盐噪声
- 确定掩膜中心和掩膜大小
- 将掩膜内像素按亮度值大小排序
- 取中值,若为偶数则取中间两个的均值
边缘检测
- 设计平滑滤波器,计算
- 检测局部最大值或者过零点
- 平滑滤波器特点:
- %3D0#card=math&code=%5Clim%5Climits_%7B%7Cx%7C%5Cto%20%5Cinfty%7Dh%28x%29%3D0&id=eZf2V)
- h(x)为偶函数
- dx%3D1#card=math&code=%5Cint_%7B-%5Cinfty%7D%5E%7B%5Cinfty%7Dh%28x%29dx%3D1&id=UjhZS),保证滤波后不改变原信号的均值
- 一阶二阶可微
常见算子
- Robert
- Prewitt
- Sobel
- Laplacian
```python def Robert_detection(img, threshold=-1): kernel1 = np.array([[-1, 0], [0, 1]]) kernel2 = np.array([[0, -1], [1, 0]]) img1 = cv2.filter2D(img, cv2.CV_32F, kernel1) # 获取-45°方向的偏导 img2 = cv2.filter2D(img, cv2.CV_32F, kernel2) # 获取-135°方向的偏导 mag = cv2.magnitude(img1, img2) mag = cv2.convertScaleAbs(mag) if threshold == -1: # 如果没有给定阈值则通过Otsu二值化_, mag = cv2.threshold(mag, 0, 255, cv2.THRESH_OTSU)
else:
mag[mag >= threshold] = 255 mag[mag < threshold] = 0
return mag
def Sobeldetection(img, threshold=-1): dx = cv2.Sobel(img, cv2.CV_32F, 1, 0) # 获取水平方向的偏导 dy = cv2.Sobel(img, cv2.CV_32F, 0, 1) # 获取竖直方向的偏导 mag = cv2.magnitude(dx, dy) mag = cv2.convertScaleAbs(mag) if threshold == -1: , mag = cv2.threshold(mag, 0, 255, cv2.THRESH_OTSU) else: mag[mag >= threshold] = 255 mag[mag < threshold] = 0 return mag
def Prewittdetection(img, threshold=-1): kernel1 = np.array([[-1, -1, -1], [0, 0, 0], [1, 1, 1]]) kernel2 = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]]) dx = cv2.filter2D(img, cv2.CV_32F, kernel2) dy = cv2.filter2D(img, cv2.CV_32F, kernel1) mag = cv2.magnitude(dx, dy) mag = cv2.convertScaleAbs(mag) if threshold == -1: , mag = cv2.threshold(mag, 0, 255, cv2.THRESH_OTSU) else: mag[mag >= threshold] = 255 mag[mag < threshold] = 0 return mag
def Laplaciandetection(img, threshold=-1): out = cv2.Laplacian(img, cv2.CV_32F, ksize=3) out = cv2.convertScaleAbs(out) if threshold == -1: , out = cv2.threshold(out, 0, 255, cv2.THRESH_OTSU) else: out[out >= threshold] = 255 out[out < threshold] = 0 return out
- ![](https://g.yuque.com/gr/latex?%5Csigma#card=math&code=%5Csigma&id=FGmVl)越大,图像分辨率越低
- Canny边缘检测
1. 与二维高斯函数做卷积,**消除噪声**
1. 计算每个像素的梯度大小和方向
1. 根据梯度方向,作非极大值抑制获取边缘位置<br />3.1. 遍历非0梯度的像素,根据梯度方向找到两个邻接像素<br />3.2. 若存在一个邻接像素梯度幅值大于该像素,则将该像素置零<br />**注:在实际运用中邻接像素的幅值通过线性插值获得**
1. 滞后阈值化处理/双阈值法<br />4.1. 设置高低阈值<br />4.2. 超过高阈值的设为边缘,弱于低阈值的舍弃<br />4.3. 遍历处于高低阈值区间内的像素,若该像素与边缘邻接则标记为边缘
- 多尺度特征综合
1. 标记最小尺度的边缘
1. 高斯卷积后估计大尺度检测边缘位置(大尺度合成边缘响应)
1. 大尺度滤波器检测(大尺度实际边缘响应)
1. 实际边缘响应显著强于合成边缘响应,则接受此边缘点
<a name="00a1ff9a"></a>
### 图像复原
- 图像增强:使图像具有更好的视觉效果
- 图像复原:利用图像降质过程的先验知识建立**降质模型**,是降质的逆过程
- 逆滤波:退化函数已知,通过复原滤波器消除退化。适用于**没有被噪声污染**的情况
![](https://g.yuque.com/gr/latex?%5Cbegin%7Balign%7D%0Ag(x%2Cy)%26%3DH%5Bf(x%2Cy)%5D%2Bn(x%2Cy)%5C%5C%0Ag(x%2Cy)%26%3Dh(x%2Cy)*f(x%2Cy)%2Bn(x%2Cy)%5C%5C%0AG(u%2Cv)%26%3DH(u%2Cv)F(u%2Cv)%2BN(u%2Cv)%5C%5C%0AF(u%2Cv)%26%3DG(u%2Cv)H%5E%7B-1%7D(u%2Cv)-N(u%2Cv)H%5E%7B-1%7D(u%2Cv)%0A%5Cend%7Balign%7D%0A#card=math&code=%5Cbegin%7Balign%7D%0Ag%28x%2Cy%29%26%3DH%5Bf%28x%2Cy%29%5D%2Bn%28x%2Cy%29%5C%5C%0Ag%28x%2Cy%29%26%3Dh%28x%2Cy%29%2Af%28x%2Cy%29%2Bn%28x%2Cy%29%5C%5C%0AG%28u%2Cv%29%26%3DH%28u%2Cv%29F%28u%2Cv%29%2BN%28u%2Cv%29%5C%5C%0AF%28u%2Cv%29%26%3DG%28u%2Cv%29H%5E%7B-1%7D%28u%2Cv%29-N%28u%2Cv%29H%5E%7B-1%7D%28u%2Cv%29%0A%5Cend%7Balign%7D%0A&id=vWQop)
H为退化函数,n为加性噪声,根据线性移不变性质可化为卷积形式(2),再进行傅里叶变换(3)
- 维纳滤波:寻找使均方误差最小的估计![](https://g.yuque.com/gr/latex?%5Chat%20f#card=math&code=%5Chat%20f&id=qni2y)
<a name="f0c164d0"></a>
## 图像分割
<a name="2e49823c"></a>
### 阈值化
- p率阈值化:基于直方图选择阈值![](https://g.yuque.com/gr/latex?T#card=math&code=T&id=KAyVV),使得![](https://g.yuque.com/gr/latex?%5Cfrac%7B1%7D%7Bp%7D#card=math&code=%5Cfrac%7B1%7D%7Bp%7D&id=i3U0b)的像素灰度值比![](https://g.yuque.com/gr/latex?T#card=math&code=T&id=UPvcN)小
- 模式方法:寻找直方图两个局部极大值,取它们之间的极小值为阈值
- 最优阈值化:
1. 设定初始阈值![](https://g.yuque.com/gr/latex?t_0#card=math&code=t_0&id=teH9d)
1. 计算灰度值小于![](https://g.yuque.com/gr/latex?t_0#card=math&code=t_0&id=gWhyz)的像素集合的平均值![](https://g.yuque.com/gr/latex?%5Cmu_1#card=math&code=%5Cmu_1&id=rlR6a),灰度值大于![](https://g.yuque.com/gr/latex?t_0#card=math&code=t_0&id=MP5LW)的像素集合的平均值![](https://g.yuque.com/gr/latex?%5Cmu_2#card=math&code=%5Cmu_2&id=VVr8b)
1. 新阈值![](https://g.yuque.com/gr/latex?t_1%3D%5Cfrac%7B%5Cmu_1%2B%5Cmu_2%7D%7B2%7D#card=math&code=t_1%3D%5Cfrac%7B%5Cmu_1%2B%5Cmu_2%7D%7B2%7D&id=Hp9hW)
1. 重复步骤2、3直到阈值变化足够小
- **OTSU阈值检测**:
1. 将直方图除以像素总数,进行归一化,得到像素概率分布直方图![](https://g.yuque.com/gr/latex?H#card=math&code=H&id=tTyMD)
1. 划分背景![](https://g.yuque.com/gr/latex?B#card=math&code=B&id=tcGtF)(灰度值小于等于![](https://g.yuque.com/gr/latex?t#card=math&code=t&id=LaSK9)的像素)与前景![](https://g.yuque.com/gr/latex?F#card=math&code=F&id=ZoPMQ)(灰度值大于![](https://g.yuque.com/gr/latex?t#card=math&code=t&id=ElwnN)的像素)
1. 背景、前景概率和均值计算:
![](https://g.yuque.com/gr/latex?%5Cbegin%7Baligned%7D%0A%5Comega_B(t)%26%3D%5Csum_%7Bi%3D0%7D%5EtH(i)%5C%5C%0A%5Comega_F(t)%26%3D%5Csum_%7Bi%3Dt%2B1%7D%5E%7B255%7DH(i)%5C%5C%0A%5Cmu_B(t)%26%3D%5Csum_%7Bi%3D0%7D%5Et%5Cfrac%7BiH(i)%7D%7B%5Comega_B%7D%5C%5C%0A%5Cmu_F(t)%26%3D%5Csum_%7Bi%3Dt%2B1%7D%5E%7B255%7D%5Cfrac%7BiH(i)%7D%7B%5Comega_F%7D%5C%5C%0A%5Cmu%26%3D%5Csum_%7Bi%3D0%7D%5E%7B255%7DiH(i)%0A%5Cend%7Baligned%7D%0A#card=math&code=%5Cbegin%7Baligned%7D%0A%5Comega_B%28t%29%26%3D%5Csum_%7Bi%3D0%7D%5EtH%28i%29%5C%5C%0A%5Comega_F%28t%29%26%3D%5Csum_%7Bi%3Dt%2B1%7D%5E%7B255%7DH%28i%29%5C%5C%0A%5Cmu_B%28t%29%26%3D%5Csum_%7Bi%3D0%7D%5Et%5Cfrac%7BiH%28i%29%7D%7B%5Comega_B%7D%5C%5C%0A%5Cmu_F%28t%29%26%3D%5Csum_%7Bi%3Dt%2B1%7D%5E%7B255%7D%5Cfrac%7BiH%28i%29%7D%7B%5Comega_F%7D%5C%5C%0A%5Cmu%26%3D%5Csum_%7Bi%3D0%7D%5E%7B255%7DiH%28i%29%0A%5Cend%7Baligned%7D%0A&id=csanq)<br />
4. 计算类间方差:
![](https://g.yuque.com/gr/latex?%5Csigma(t)%3D%5Comega_B(t)(%5Cmu_B(t)-%5Cmu)%5E2%2B%5Comega_F(t)(%5Cmu_F(t)-%5Cmu)%5E2%0A#card=math&code=%5Csigma%28t%29%3D%5Comega_B%28t%29%28%5Cmu_B%28t%29-%5Cmu%29%5E2%2B%5Comega_F%28t%29%28%5Cmu_F%28t%29-%5Cmu%29%5E2%0A&id=o7SSY)<br />
5. 最优阈值![](https://cdn.nlark.com/yuque/__latex/995130d8a020469b78878b1f8c4764aa.svg#card=math&code=%5Chat%20t%3D%5Cunderset%7Bt%7D%7Bargmax%7D%28%5Csigma%28t%29%29&height=33&id=a2hS3)
```python
def Otsu(img):
# 获取直方图并归一化
hist = cv2.calcHist([img], [0], None, [256], [0, 256])[:, 0]
hist /= np.sum(hist)
# 取直方图中非零索引
nonzero_index = np.nonzero(hist)[0]
# min_index和max_index代表灰度级的最低值与最高值
[min_index, max_index] = nonzero_index[[0, -1]]
# sigma存储以各非零索引的灰度级作为阈值的类间方差
sigma = np.zeros_like(nonzero_index)
for i in range(len(nonzero_index)):
t = nonzero_index[i]
# 根据阈值t将直方图划分为两部分
before = hist[min_index:t + 1]
after = hist[t + 1:max_index + 1]
# 计算两部分的概率
P_before = np.sum(before)
P_after = np.sum(after)
# 计算三种均值
miu_before = np.sum(np.arange(min_index, t + 1) * before / P_before)
miu_after = np.sum(np.arange(t + 1, max_index + 1) * after / P_after)
miu = np.sum(np.arange(min_index, max_index + 1) * hist[min_index: max_index + 1])
# 计算此时的类间方差
sigma[i] = P_before * (miu_before - miu) ** 2 + P_after * (miu_after - miu) ** 2
# 取sigma最大的索引就可以读取出对应阈值
threshold = nonzero_index[np.argmax(sigma)]
Binary = img.copy()
Binary[img >= threshold] = 255
Binary[img < threshold] = 0
return Binary
边界跟踪
内边界跟踪
- 从左上方开始搜索,设定%2F7(8-%E9%82%BB%E6%8E%A5)#card=math&code=dir%3D3%284-%E9%82%BB%E6%8E%A5%29%2F7%288-%E9%82%BB%E6%8E%A5%29&id=WkrcE)
- 按逆时针方向搜索邻域,初始方向为:
%5Cmod%204%5C%5C%0A8-%E9%82%BB%E6%8E%A5%E8%B7%9F%E8%B8%AA%EF%BC%9A%26dir%3D(dir%2B7)%5Cmod%208%EF%BC%88dir%E4%B8%BA%E5%81%B6%E6%95%B0%EF%BC%89%5C%5C%0A%26dir%3D(dir%2B6)%5Cmod%208%EF%BC%88dir%E4%B8%BA%E5%A5%87%E6%95%B0%EF%BC%89%0A%5Cend%7Baligned%7D%0A#card=math&code=%5Cbegin%7Baligned%7D%0A4-%E9%82%BB%E6%8E%A5%E8%B7%9F%E8%B8%AA%EF%BC%9A%26dir%3D%28dir%2B3%29%5Cmod%204%5C%5C%0A8-%E9%82%BB%E6%8E%A5%E8%B7%9F%E8%B8%AA%EF%BC%9A%26dir%3D%28dir%2B7%29%5Cmod%208%EF%BC%88dir%E4%B8%BA%E5%81%B6%E6%95%B0%EF%BC%89%5C%5C%0A%26dir%3D%28dir%2B6%29%5Cmod%208%EF%BC%88dir%E4%B8%BA%E5%A5%87%E6%95%B0%EF%BC%89%0A%5Cend%7Baligned%7D%0A&id=FyWy8)
简单来说对于4邻接跟踪,更新后的为之前的(顺时针转90°);对于8邻接跟踪,更新后的为之前的顺时针转至第一个奇数位
例如:4邻接,更新后的;8邻接,更新后的
3. 当前像素等于第二个像素,且上一个像素等于第一个像素时停止;否则重复步骤2
def InnerTrack(img):
# 生成对应边界矩阵
output = np.zeros_like(img)
# 8×2的矩阵表示各方向下的移动情况
steps = np.array([[0, 1], [-1, 1], [-1, 0], [-1, -1],
[0, -1], [1, -1], [1, 0], [1, 1]])
rows, cols = img.shape
for row in range(rows):
for col in range(cols):
# 当原图中该点亮度不为0(即白色背景),或边界图像为255(即该点已经处理过),或以该点为中心的3×3边界矩阵有大于0的(该点附近有处理过的边界)
# 或以该点为中心的3×3原图矩阵均为0(即目标图像中心区域)——这四种情况发生时都要略过
if img[row, col] != 0 or output[row, col] == 255 or np.sum(output[row-1:row+2, col-1:col+2]) > 0 or np.sum(img[row-1:row+2, col-1:col+2]) == 0:
continue
next_pos = [row, col]
next_dir = 7
while next_pos:
next_pos, next_dir = Track(img, output, next_pos, next_dir, steps)
return output
def Track(img, output, pos, dir, steps):
# 设定初始方位
dir = (dir + 6) % 8 if dir % 2 else (dir + 7) % 8
# 将初始点标记
output[pos[0], pos[1]] = 255
# 遍历各方向
for i in range(8):
next_dir = (dir + i) % 8
# 确定下一步的方位
[row, col] = pos + steps[next_dir]
# 只有当下一步没越界并且原图中该点是黑色时继续处理
if 0 <= row < img.shape[0] and 0 <= col < img.shape[1] and img[row, col] == 0:
# 如果这时边界矩阵仍是0,表示没被处理过,可以继续处理
if output[row, col] == 0:
# 返回下一步的位置和方向
return [row, col], next_dir
# 如果处理过直接结束,内边界跟踪结束
return None, None
return None, None
外边界跟踪
- 进行4邻接跟踪
- 搜索过程中测试过的非内边界像素组成外边界
扩展边界
- 边界形状与内边界完全相同,像素位置向下和向右平移了半个像素
- 对于内边界而言:扩展边界为内边界的上、左像素;右像素的右方、下方、右下方像素;下像素的下方、右方像素
- 对于外边界而言:扩展边界为上像素向右下移动1个像素;左像素向右移动1个像素;右像素向下移动1个像素
- 查找表法追踪边界:按照12种情况的表进行追踪
基于区域分割
- 分裂与归并:
- 金字塔数据结构种,任意区域不符合一致性测试,则分裂成四个子区域;如果具有相同父结点的四个区域具有一致性,则归并
- 执行步骤1至无法分裂与归并
- 归并任意两个具有一致性的邻接区域(可没有相同父结点)
- 如果必须删除小尺寸,则归并小区域和最相似的邻接区域
- 一致性规则可自定义,例如天鹅星座环的X射线频段图像中,需要分割出稀疏环(标准差较大且灰度值介于背景和中心区域之间)。此时可定义为一致性为.
分水岭分割
对于梯度幅值图像而言,盆地表示原图像平滑的地方。给定幅值初始值的情况下,每个幅值小于初始值的盆地表示一个区域。按照幅值大小从初始值往上遍历,对于新像素而言它将分给离它邻接的盆地。如果它和两个盆地都邻接,则为分水岭。如果它没有邻接盆地,则为新盆地。
数学形态学
二值图像形态学
- 反射:%7C(x%2Cy)%5Cin%20B%5C%7D#card=math&code=%5Chat%20B%3D%5C%7B%28-x%2C-y%29%7C%28x%2Cy%29%5Cin%20B%5C%7D&id=eejIs)
- 平移:_z%3D%5C%7Bc%7Cc%3Db%2Bz%2C%20b%5Cin%20B%5C%7D#card=math&code=%28B%29_z%3D%5C%7Bc%7Cc%3Db%2Bz%2C%20b%5Cin%20B%5C%7D&id=F1Hkj)
- 膨胀:_z%5Ccap%20A%20%5Cneq%20%5Cvarnothing%5C%7D#card=math&code=A%5Coplus%20B%3D%5C%7Bz%7C%28%5Chat%20B%29_z%5Ccap%20A%20%5Cneq%20%5Cvarnothing%5C%7D&id=sE96G)
- 腐蚀:
- 对偶性:
%5Ec%3DA%5Ec%5Coplus%20%5Chat%20B%5C%5C%0A(A%5Coplus%20B)%5Ec%3DA%5Ec%5Ccircleddash%20%5Chat%20B%0A#card=math&code=%28A%5Ccircleddash%20B%29%5Ec%3DA%5Ec%5Coplus%20%5Chat%20B%5C%5C%0A%28A%5Coplus%20B%29%5Ec%3DA%5Ec%5Ccircleddash%20%5Chat%20B%0A&id=j0lMb)
对于原点对称结构元来说,对背景膨胀的补集等于对的腐蚀
- 击中击不中变换:,其中为与目标匹配的模板,为与目标背景匹配的模板。用于在A中寻找与模板B匹配的元素
- 开运算:%5Coplus%20B#card=math&code=A%5Ccirc%20B%3D%28A%5Ccircleddash%20B%29%5Coplus%20B&id=zQvyD),平滑物体轮廓,断开狭颈,去掉细小突出
- 闭运算:%5Ccircleddash%20B#card=math&code=A%5Cbullet%20B%3D%28A%5Coplus%20B%29%5Ccircleddash%20B&id=Rc7NN),平滑物体轮廓,弥合较窄间断和细长沟壑,消除小孔,填补轮廓线中的断裂
膨胀运算的例子:
结构元反射后,根据中元素坐标对平移,若平移后的_z#card=math&code=%28%5Chat%20B%29_z&id=rvVf5)与仍有交集则该元素属于膨胀结果集合
如上图所示,的原点在左下角。#card=math&code=%280%2C0%29&id=pZfEO)坐标的变换结果_z%3D%5C%7B(-1%2C0)%2C(0%2C0)%5C%7D#card=math&code=%28%5Chat%20B%29_z%3D%5C%7B%28-1%2C0%29%2C%280%2C0%29%5C%7D&id=p9Gye)与不相交,所以%5Cnot%5Cin%20A%5Coplus%20B#card=math&code=%280%2C0%29%5Cnot%5Cin%20A%5Coplus%20B&id=BNCU0)。
而对于#card=math&code=%281%2C4%29&id=rWK9n)坐标的变换结果_z%3D%5C%7B(0%2C4)%2C(1%2C4)%5C%7D#card=math&code=%28%5Chat%20B%29_z%3D%5C%7B%280%2C4%29%2C%281%2C4%29%5C%7D&id=AHRJj)与相交,则%5Cin%20A%5Coplus%20B#card=math&code=%281%2C4%29%5Cin%20A%5Coplus%20B&id=dI9jc)。
特征检测
角点检测
- 角点是在邻域内的各个方向上灰度变化值足够高的点
- 角点是图像边缘曲线上曲率极大值的点
- 角点检测的准则:
- 角点检测的正确性:不检测出错的角点
- 角点定位的准确性:位置不能有过大的偏差
- 角点检测算法稳定性与效率:受噪音影响小
- Moravec角点检测:任意方向移动窗口,若窗口内灰度值都有剧烈变化则窗口中心为角点
- 变化值:%3D%5Csum%20w(x_i%2Cy_i)%5BI(x_i%2Cy_i)-I(x_i%2B%5CDelta%20x%2Cy_i%2B%5CDelta%20y)%5D%5E2#card=math&code=E%28%5CDelta%20x%2C%20%5CDelta%20y%29%3D%5Csum%20w%28x_i%2Cy_i%29%5BI%28x_i%2Cy_i%29-I%28x_i%2B%5CDelta%20x%2Cy_i%2B%5CDelta%20y%29%5D%5E2&id=NTokL),%E5%8F%96(1%2C0)%2C(1%2C1)%2C(0%2C1)%2C(-1%2C1)#card=math&code=%28%5CDelta%20x%2C%20%5CDelta%20y%29%E5%8F%96%281%2C0%29%2C%281%2C1%29%2C%280%2C1%29%2C%28-1%2C1%29&id=CseKC)
- 角点响应函数%3D%5Cmin%7BE(%5CDelta%20x%2C%20%5CDelta%20y)%7D#card=math&code=R%28x_i%2C%20y_i%29%3D%5Cmin%7BE%28%5CDelta%20x%2C%20%5CDelta%20y%29%7D&id=qPiOX)
- 将响应函数中低于阈值的值设为0
- 非极大值抑制:遍历角点响应函数,若角点响应在窗口内不是最大则置0
- 选择非零点作为角点检测结果
- Harris角点检测:使用高斯函数作为窗口
- 自相关矩阵M的响应函数-k(trace(M))%5E2#card=math&code=R%3Ddet%28M%29-k%28trace%28M%29%29%5E2&id=hXGK2) | 特征值关系 | 响应函数R | | —- | —- | | | |
SIFT
- 检测尺度空间的极值点
精确定位特征点(Keypoint)
- 去除不稳定极值点
- 去除边缘响应过大的极值点:计算差分图像D的Hessian矩阵
满足
设定特征点的方向参数
- 在高斯尺度空间计算像素梯度
%3D%5Csqrt%7B%5BL(x%2B1%2Cy)-L(x-1%2Cy)%5D%5E2%2B%5BL(x%2Cy%2B1)-L(x%2Cy-1)%5D%5E2%7D%5C%5C%0A%5Ctheta(x%2Cy)%3D%5Carctan%5Cfrac%7BL(x%2Cy%2B1)-L(x%2Cy-1)%7D%7BL(x%2B1%2Cy)-L(x-1%2Cy)%7D%0A#card=math&code=m%28x%2Cy%29%3D%5Csqrt%7B%5BL%28x%2B1%2Cy%29-L%28x-1%2Cy%29%5D%5E2%2B%5BL%28x%2Cy%2B1%29-L%28x%2Cy-1%29%5D%5E2%7D%5C%5C%0A%5Ctheta%28x%2Cy%29%3D%5Carctan%5Cfrac%7BL%28x%2Cy%2B1%29-L%28x%2Cy-1%29%7D%7BL%28x%2B1%2Cy%29-L%28x-1%2Cy%29%7D%0A&id=Fls2M)
- 建立梯度方向直方图,横轴为角度,范围0~360°
- 直方图峰值对应的方向为主方向
- 能量超过主峰值80%的次峰对应的方向为辅方向
- 生成特征点的描述子(128维向量)
- 将坐标轴方向旋转至特征点的方向
- 对每个特征点为中心取窗口,高斯加权增强特征点附近的像素的贡献
- 将窗口分为的小块,每块计算8个方向的梯度方向直方图
- 每个特征点用维向量描述
SURF
特征点描述子为64维
特征点匹配
- 特征点的数据结构包含:
- 位置坐标
- 尺度
- 方向
- 特征向量
- 根据特征向量欧氏距离找出最近邻和次近邻,如果最近邻比次近邻小于阈值,则匹配成功
HOG
- 通过局部梯度、边缘方向分布描述局部目标,而不需要知道对应的梯度、边缘的位置
- 图像归一化
- 灰度化
- 归一化:gamma校正降低图像局部的阴影和光照变化所造成的影响
计算图像梯度
- 计算无符号的梯度方向
%3D%5Cleft%5C%7B%0A%5Cbegin%7Baligned%7D%0A%26%5Ctheta(x%2Cy)%2B%5Cpi%5Cquad%20%5Ctheta(x%2Cy)%3C0%5C%5C%0A%26%5Ctheta(x%2Cy)%5Cquad%20others%0A%5Cend%7Baligned%7D%0A%5Cright.%0A%5Cend%7Baligned%7D%0A#card=math&code=%5Cbegin%7Baligned%7D%0A%5Ctheta%28x%2Cy%29%3D%5Cleft%5C%7B%0A%5Cbegin%7Baligned%7D%0A%26%5Ctheta%28x%2Cy%29%2B%5Cpi%5Cquad%20%5Ctheta%28x%2Cy%29%3C0%5C%5C%0A%26%5Ctheta%28x%2Cy%29%5Cquad%20others%0A%5Cend%7Baligned%7D%0A%5Cright.%0A%5Cend%7Baligned%7D%0A&id=rMEip)
在细胞单元构建梯度直方图
- 将细胞单元内每个像素按照方向划分成9块
- 按照方向将幅值划分到不同的块:比如165度方向上的幅值为85,则
块内梯度直方图对比度归一化
- 按照二范数进行归一化
- 计算HOG特征描述子
Hough变换
%0A#card=math&code=y_i%3Dax_i%2Bb%5Crightarrow%20b%3D-x_ia%2By_i%28x_i%2Cy_i%E5%9B%BA%E5%AE%9A%29%0A&id=tZ2BT)
%2C(x_j%2Cy_j)%E5%9C%A8%E7%9B%B4%E7%BA%BFy%3Dax%2Bb%E4%B8%8A%5C%5C%0A%E5%88%99%E6%9C%89%0A%5Cleft%5C%7B%0A%20%20%5Cbegin%7Baligned%7D%0A%20%20b%3D-x_ia%2By_i%5C%5C%0A%20%20b%3D-x_ja%2By_j%0A%20%20%5Cend%7Baligned%7D%0A%5Cright.%0A#card=math&code=%28x_i%2Cy_i%29%2C%28x_j%2Cy_j%29%E5%9C%A8%E7%9B%B4%E7%BA%BFy%3Dax%2Bb%E4%B8%8A%5C%5C%0A%E5%88%99%E6%9C%89%0A%5Cleft%5C%7B%0A%20%20%5Cbegin%7Baligned%7D%0A%20%20b%3D-x_ia%2By_i%5C%5C%0A%20%20b%3D-x_ja%2By_j%0A%20%20%5Cend%7Baligned%7D%0A%5Cright.%0A&id=xptph)
%2C(x_j%2Cy_j)%E5%9C%A8%E7%9B%B4%E7%BA%BF%5Crho%3Dx%5Ccos%5Ctheta%2By%5Csin%5Ctheta%E4%B8%8A%5C%5C%0A%E5%88%99%E6%9C%89%0A%5Cleft%5C%7B%0A%20%20%5Cbegin%7Baligned%7D%0A%20%20%5Crho%3Dx_i%5Ccos%5Ctheta%2By_i%5Csin%5Ctheta%5C%5C%0A%20%20%5Crho%3Dx_j%5Ccos%5Ctheta%2By_j%5Csin%5Ctheta%0A%20%20%5Cend%7Baligned%7D%0A%5Cright.%0A#card=math&code=%28x_i%2Cy_i%29%2C%28x_j%2Cy_j%29%E5%9C%A8%E7%9B%B4%E7%BA%BF%5Crho%3Dx%5Ccos%5Ctheta%2By%5Csin%5Ctheta%E4%B8%8A%5C%5C%0A%E5%88%99%E6%9C%89%0A%5Cleft%5C%7B%0A%20%20%5Cbegin%7Baligned%7D%0A%20%20%5Crho%3Dx_i%5Ccos%5Ctheta%2By_i%5Csin%5Ctheta%5C%5C%0A%20%20%5Crho%3Dx_j%5Ccos%5Ctheta%2By_j%5Csin%5Ctheta%0A%20%20%5Cend%7Baligned%7D%0A%5Cright.%0A&id=zfWm0)
- 设定参数空间为个累加单元,设置累加器矩阵Q并置零
- 对于XY平面上的点#card=math&code=%28x_i%EF%BC%8Cy_i%29&id=qt2nR),令等于轴上所有允许的细分值,计算对应的。(根据一个点在参数空间画出一条正弦曲线)
- 将四舍五入成最接近的细分值
- 在Q中找出对应单元加1
- 重复2-4步,最终Q值最大的单元对应的即为直线方程参数
- 直线检测的精度取决于两个参数细分值的大小
- 如果参数空间细分过粗,则参数的凝聚效果较差,找不出直线对应的准确参数
- 细分值也不能过小,会增大算法第2步的计算量
| 检测方法 | 优点 | 缺点 |
| —- | —- | —- |
| Moravec角点 | - | 二值窗口函数,角点响应函数不够光滑
四个方向上计算,角点响应函数在多处都有响应
只考虑E的最小值,对边缘也有很强的响应 | | Harris角点 | 计算简单
提取的点均匀且合理
算子对图像旋转、亮度变化、噪声影响和视点变换不敏感 | 对尺度敏感
角点精度是像素级
需要设计角点匹配算法 | | SIFT匹配 | 对旋转、尺度缩放、亮度变化保持不变性
对视角变化、仿射变换、噪声保持一定的稳定性
信息量丰富,适用于匹配
少数物体也能产生大量SIFT特征 | - | | HOG | 表示梯度/边缘的结构特征,可以描述局部的形状信息
位置和方向的量化,一定程度上可以抑制平移和旋转的影响
局部区域归一化直方图,可以部分抵消光照变化带来的影响
分块分单元的处理方法,使得图像局部像素点之间的关系可以很好得到的表征 | 描述子生成过程冗长,导致速度慢,实时性差
很难处理遮挡问题
由于梯度的性质,HOG对噪点相当敏感 |
立体视觉
- 立体视觉:由多幅图像获取物体的三维几何信息
- 基本步骤:
- 摄像机标定
- 多幅图像中建立对应点对
- 重构场景中的三维坐标
摄像机标定
- 姿态描述:在物体上固定一个坐标系{B},给出此坐标系相对于参考坐标系{A}的表达
- 位姿描述:在三维空间中表示物体的位置和姿态
- 过渡坐标系:将坐标变换分解为旋转、平移;过渡坐标系的姿态和A相同,原点和B重合
旋转矩阵
- 绕x轴顺时针旋转:
- 绕y轴顺时针旋转:
- 绕z轴顺时针旋转:
齐次坐标变换:
- 齐次变换矩阵
- 线性摄像机成像:世界坐标系-相机坐标系-物理单位表示的图像坐标系-像素单位表示的图像坐标系
- 摄像机外参数:6个独立外参
- 摄像机内参数:
- u/v轴互相垂直:4个独立内参
- u/v轴不垂直:5个独立内参
- 单透视摄像机成像:欧式世界坐标系-欧式相机坐标系-欧式图像坐标系-图像仿射坐标系
- 透视投影矩阵M有11个自由参数,求解M需要6个对应点对
- 参数模型的最优化估计
- 最大似然概率估计
- 线性估计
- 叉积矩阵
- 鲁棒估计
- 畸变与失真
- 径向失真
- 光线在远离透镜中心的地方比靠近中心的地方更弯曲
- 对于径向失真,摄像机中心的畸变为零,随着向边缘移动,畸变越来越严重
- 径向失真
- 切向失真
- 由于透镜制造上的缺陷,使透镜本身与成像平面不平行
- 径向畸变只会导致径向失真
- 离心畸变、薄透镜畸变会导致径向、切向失真
- 直接线性变换DLT标注法:
- 根据n个点对确定2n个方程
张正友平面标定法
- 将世界坐标系置于靶标平面,原点设在靶标的一角。其中方向沿靶标平面,方向垂直于靶标平面。
- 优点:
- 靶标平面上的点的世界坐标系坐标便于确定
- 靶标平面上的点的Z方向坐标恒为0,三维坐标只与有关,可以简化为二维坐标
- 步骤:
- 不考虑畸变,标定摄像机参数,得到参数的线性初值
- 利用线性初值,进行非线性标定,得到畸变参数
- 重复1和2,直至参数收敛
- 单应性矩阵给出从一个平面到另一个平面的映射,它包括摄像机内外参数矩阵
- 具体解法
- 保持相机位置不变,将标定板置于不同位置采集m幅图像,每个图像n个角点
- 遍历每幅图像,求解单应性矩阵初值(2n个方程,9个未知数);再进行非线性优化,获取单应性矩阵
- 综合m幅图像的单应性矩阵,求解方程vb=0(2m个方程,6个未知数),将中间矩阵B分解,获取内参数矩阵(5个参数)
- 由H和计算每幅图像的R和P
- 综合m幅图像中n个角点求解Ak=B(2mn个方程,2个未知数),得到畸变系数
- 参数最优化:通过非线性最小二乘法优化内参数矩阵(5个参数),R和P(6m个参数),
对极几何
- 基线:两个相机光心连线
- 极面:观察点P与两相机光心构成的平面
- 极线:图像上对应于图像中点的极线——极面与的交线
- 对极约束:对应于图像上的点在图像上的对应点一定落在图像的极线上
作用:将,对应点的搜索空间的维度由2维降为1维
- 极点:所有极线交汇的那一点,也是连线与图像的交点,也是光心到另一图像的投影点
- 极线方程:
若给定则公式为关于的线性方程,即图像上的极线方程;若给定则同理。
其中对于三维向量
且满足
- 基础矩阵:
F由相机参数矩阵确定,若对应点已知,则F包含了从一对图像中可以恢复出的所有信息