计算机视觉Stanford

计算机视觉-hw

hw0

获取矩阵特征值与特征向量。图像裁剪、旋转、平移、缩放,像素值调整(变暗|变亮)

图像缩放:

def resize_image(input_image, output_rows, output_cols):
 """Resize an image using the nearest neighbor method.
 """
 input_rows, input_cols, channels = input_image.shape
 assert channels == 3

 # 1. Create the resized output image
 output_image = np.zeros(shape=(output_rows, output_cols, 3))

 # 2. Populate the `output_image` array using values from `input_image`
 #    > This should require two nested for loops!

 row_scale_factor = input_rows / output_rows
 col_scale_factor = input_cols / output_cols
 for i in range(output_rows):
     for j in range(output_cols):
         output_image[i,j] = input_image[int(i*row_scale_factor),int(j*col_scale_factor)]

 return output_image

图像旋转:

def rotate2d(point, theta):
 """Rotate a 2D coordinate by some angle theta."""
 assert point.shape == (2,)
 assert isinstance(theta, float)

 # Reminder: np.cos() and np.sin() will be useful here!

 out_point = np.array([0.0,0.0])
 out_point[0] = point[0]*np.cos(theta) - point[1]*np.sin(theta)
 out_point[1] = point[0]*np.sin(theta) + point[1]*np.cos(theta)
 return out_point


def rotate_image(input_image, theta):
 """Rotate an image by some angle theta."""
 input_rows, input_cols, channels = input_image.shape
 assert channels == 3

 # 1. Create an output image with the same shape as the input
 output_image = np.zeros_like(input_image)

 center_point = np.array([input_rows/2, input_cols/2])
 # input_rows = output_rows,input_cols = output_cols,因此迭代input的行和列即可
 for i in range(input_rows):
     for j in range(input_cols):
         output_point = np.array([i,j])
         # 可以看出图像是顺时针旋转,因此从输出图像逆时针旋转theta角度查看原图的点的位置
         input_point = rotate2d(output_point-center_point, theta) + center_point
         if 0 <= input_point[0] < input_rows and 0 <= input_point[1] < input_cols:
             output_image[i,j] = input_image[int(input_point[0]),int(input_point[1])]
         else:
             continue

 return output_image

hw1

**卷积:**首先将图像垂直翻转,再水平翻转(相当于旋转180度),再进行计算。其定义如下

f [ m , n ] ∗ h [ m , n ] = ∑ i = − ∞ ∞ ∑ j = − ∞ ∞ f [ i , j ] ⋅ g [ m − i , n − j ] f[m,n]*h[m,n]=\sum_{i=-\infty}^\infty\sum_{j=-\infty}^\infty f[i,j]\cdot g[m-i,n-j] f[m,n]h[m,n]=i=j=f[i,j]g[mi,nj]

互相关:(用于模板匹配)

图像f与模板g的互相关如下:

( g ∗ ∗ f ) [ m , n ] = ∑ i = − ∞ ∞ ∑ j = − ∞ ∞ f [ i , j ] ⋅ g [ i − m , j − n ] (g ** f)[m,n]=\sum_{i=-\infty}^\infty\sum_{j=-\infty}^\infty f[i,j]\cdot g[i-m,j-n] (gf)[m,n]=i=j=f[i,j]g[im,jn]

当在某图片中要寻找物体g时,可以使用互相关函数,图片输出中大于设定阈值的部分可以看作是匹配成功。

零均值互相关:

将模板g减去自己的均值,再进行互相关

归一化互相关:

零均值互相关对光照条件的变化不稳健,因此提出了归一化互相关。对g进行归一化,并在计算每个输出像素时,将f中与g大小的像素进行归一化

可分离过滤器:

I ∗ F = ( I ∗ F 1 ) ∗ F 2 I*F = (I*F_1)*F_2 IF=(IF1)F2

hw2

canny边缘检测:

步骤:

1、使用高斯滤波器,对原图进行滤波(高斯核可以很好的抑制呈正态分布的噪声)——kernel_size和sigma越大,经滤波后的图像越模糊

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3GqAC8XQ-1639120163612)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20211012150856268.png)]

2、求梯度

从x方向和y方向分别求得每个像素值坐标处的梯度Gx和Gy,那么可以计算出此处的梯度 G = G x 2 + G y 2 G=\sqrt{Gx^2+Gy^2} G=Gx2+Gy2 ,方向 θ = a r c t a n G y G x \theta = arctan\frac{Gy}{Gx} θ=arctanGxGy

3、非极大值抑制

将每个像素处的梯度指定到离其最近的45度方向(东南西北、东北、东南、西北、西南)代码:

theta = np.floor((theta+22.5)/45)*45

对于每个像素(边界除外),将其值与其梯度方向和负梯度方向的像素值进行比较,若均大于则保留,否则置为0。

4、双阈值判定

由阈值high和low判定强边和弱边(介于low和high),并用布尔值分别记录为strong_edges和weak_edges。

5、边缘追踪(连通性分析)哈

对于大于high的梯度值,我们可以认为它就是边缘,而介于high和low之间的梯度值,我们怀疑它可能是由噪声引起的。由于噪声是随机且独立的,因此可以把出现在强边缘八邻域内的弱边看作真的边缘,而去除孤立存在的弱边。

用代码实现时可以使用BFS。现将强边的八邻域加入queue中,再迭代queue中的每一个元素,若它是弱边且还未划分为真的边缘(强边),则将它划分为强边,且追加它的八邻域到queue中。

霍夫变换:

1、进行canny检测

2、提取感兴趣的区域(Extracting Region Of Interest,ROI)

3、霍夫变换

将y = ax + b转换到参数空间:b = -xa + y。此时(a,b)是参数空间中的一个点。在原图中旋转经过(x,y)的直线,得到参数空间中斜率不变(因为x和y没有变化)的一条直线(a和b在变化)。这样,遍历所有的边缘坐标(x,y),对于每一个(x,y)可以绘制参数空间的一条直线,在参数空间中某点(a,b)的相交数大于一定阈值时,可以认为这是原图中的一条直线。

由于y=ax+b不能表示平行于y轴的直线,因此转换到参数空间: ρ = x cos ⁡ θ + y sin ⁡ θ \rho = x\cos\theta + y\sin\theta ρ=xcosθ+ysinθ

hw3——panorama图像拼接

Harries角点检测:

求图像在x、y轴上的导数,选定window_size,对于每一个window,求:
M i j = [ ∑ w I x I x ∑ w I x I y ∑ w I x I y ∑ w I y I y ] M_{ij}=\left[\begin{matrix} \sum_w I_xI_x & \sum_w I_xI_y \\ \sum_w I_xI_y & \sum_w I_yI_y \\ \end{matrix}\right] Mij=[wIxIxwIxIywIxIywIyIy]
其中每一个元素相当于用尺寸为window_size的kernel对图像进行卷积

计算角响应函数 R = λ 1 λ 2 − k λ 1 λ 2 = d e t ( M ) − t r ( M ) R=\lambda_1\lambda_2 - k\lambda_1\lambda_2=det(M)-tr(M) R=λ1λ2kλ1λ2=det(M)tr(M)

接下来进行非极大值抑制双阈值判断link_edges,得到keypoints(它是一个个像素点的集合)

建立描述符:

simple descriptor:选定patch_size。对于每一个keypoint,用patch_size×patch_size个像素值组成向量,对其进行归一化得到feature。

HoG descriptor:与simple descriptor不同,HoG使用梯度信息来对keypoints进行描述。先选定patch_size,即block的大小,而对于一个block,再选定cell的大小。在每一个cell中利用梯度大小及其方向(在[0,180°]区间内)构建梯度直方图。如何构建梯度直方图呢?将180°分为9个bins([0,20°),…[160°,180°]),将一个cell中所有像素的梯度值按比例投入到各个bins中。这样,每个cell就有一个长度为9的向量,再将block中所有cell的向量组合在一起,并进行归一化,就得到了描述符。

对于需要进行拼接的两幅图像img1和img2,分别进行以上操作。分别获得m个和n个描述符(特征向量)

描述符匹配:

用欧氏距离作为向量距离的度量。对于img1的每个描述符des,计算img2中距离它最近的描述符des1,如果des1相对于des2足够小(即des1<des2*threshold),那么就认为这两个描述符是一个match。每一个match对应的两个描述符分别组成矩阵p1和p2。

当然,这些还不足够。为使img2拼接到img1上,需要对img2进行一个仿射变换。即使用一个Transformation Matrix H,使得 p 2 ^ H = p 1 ^ \hat{p_2}H=\hat{p_1} p2^H=p1^

由于几乎不可能使得 p 2 H = p 1 p_2H=p_1 p2H=p1,因此需要利用最小二乘法求H。因为该式缺少偏置项(,无法表示平移,需转换到齐次坐标系下),因此H是一个3×3的矩阵,两个p向量用1填充增长至3维。

由于所有的matches并非都是真正的match。因此使用RANSAC得到robust的matches以及其对应的H,该算法如下:

RANSAC:

  • 事先选定好阈值threshold和n_iters(迭代次数)
  • 在每一次迭代中,随机选取一定比例的matches(比如0.2),并计算对应的H
  • 使用此次迭代计算出来的H将所有 p 2 p_2 p2映射到 r e p r e s e n t s represents represents,计算每对 r e p r e s e n t s represents represents p 1 p_1 p1之间的欧式距离。如果这个距离小于threshold,则认为是robust_match
  • 计算此次迭代有多少个robust_match。在所有迭代中选取能使robust_match最多的那次迭代对应的H和robust_matches。

图像拼接:

利用img1、img2和H可以计算出将两幅图像拼接后输出空间的大小以及img1和img2在输出空间中的offset。之后利用这些信息,分别将img1和img2映射到输出空间,再相加。此时应注意,由于两幅图像有重合的部分,因此要先计算出img1和img2的图像分别占用了输出空间的哪些点,即mask1和mask2,之后将两个mask相加,就知道哪些部分是重合的,在让输出图像的对应像素值除以2即可。

hw6——Object Detection

步骤

下面以人脸检测为例,我们首先拥有了一套对齐的人脸数据集:

1、计算人脸均值,得到人脸模板template

2、计算模板的HOG特征,HOG特征的计算方法为:

hog_feature, hog_image = feature.hog(image, orientations=9, pixels_per_cell=(pixel_per_cell, pixel_per_cell), block_norm='L1',visualize=True)
'''可以使用skimage.feature.hog()函数, orientations控制有几个bin。一个block有几个cell可以由cells_per_block参数控制,用法通pixels_per_cell。block_norm选择对每个block计算出的向量进行归一化的方式。visualize=True表示会输出通image同等大小的hog_image。
而hog_feature是一个向量。举例说明hog_feature的计算方法:假如我们有218×178大小的图像,设定pixels_per_cell=(8,8),而cells_per_block默认为(3,3),可以计算出218//8=27,178//8=22.由于使用滑动窗口的方式计算每个block,每次滑动pixels_per_cell大小的像素距离,因此总共需要计算(27-3+1)×(22-3+1)=500个block。每个block最终计算完有3×3×orientations=81个值,进行归一化操作。它们总共可以拼接为500×81=40500个元素的向量。'''

3、对于待检测图片,首先进行padding。之后使用滑动窗口方法:窗口大小为模板大小,每次滑动步长可以事先指定为step_size。对于每一次的窗口,计算它的hog特征,得到同模板的hog_feature形状相同的向量,在两向量间进行内积,得到得分score。要找到得分最高的位置,并记录它所在的行与列,即为目标位置。

4、此为优化步骤。由于人脸尺寸可能与模板尺寸不一致,导致找不到匹配,因此提出了图像金字塔pyramid的概念。它首先生成图像的金字塔,比如我首先将图像扩展到原尺寸的1.2倍,之后按0.9的倍率缩小图像,将(scale,scaled_image)作为一个tuple追加到images的列表中,直到缩小的行或列小于某一个阈值停止。之后,将这些图片依次取出进行第三步的操作即可。

以上我没有说的是,在使用滑动窗口检测人脸时,它返回的response_map记录了在每一处的得分,可以想到它与图像尺寸不同,但在以下步骤中,我们需要得到与原图像尺寸相同的response_map,因此会使用skimage提供的resize()函数,对response_map进行插值得到与原图像同样大小的resized_response_map:

在这里插入图片描述

Deformable Parts Detection(不变形部件模型)

首先说一下我的理解,我认为它在这里实现的是同上的功能,那么可以看作是优化?

毕竟它也要使用HOG特征,图像金字塔等,那就是优化。

看完下面的步骤再看这句话:以前仅使用人脸作为模板,现在还加入了各种零件,我认为它的目的应该是增加匹配的精确性。

步骤

仍以人脸检测为例,数据集也如上。这次,我们将人脸拆解为一个个的“零件”——左眼、右眼、鼻子、嘴巴等,同时,我们也获取了它们在原对齐图像中的区域位置。

1、同计算平均人脸一样,这一次,依次计算平均“零件”(部件过滤器),并获取它们的HOG特征

2、对于待检测图片,使用人脸模板(全局过滤器)和“零件”模板(部件过滤器)依次使用图像金字塔进行滑动窗口操作,计算各自最大得分的resized_response_map

3、计算数据集中各“零件”位置到人脸模板中心的平均偏移mu,以及标准差sigma。以左眼为例,它的平均位置lefteyes=(lefteyes_x, lefteyes_y)与人脸模板中心face=(face_shape_x//2, face_shape_y//2)的距离为d=face-left_eyes。之后进行修正,将左眼的resized_response_map加上d(即得到lefteyes_heatmap_shifted)。可以想象,它其实就是“将左眼移动到脸中心位置上”。

4、最后,使用各“零件”的sigma对它们的heatmap_shifted进行高斯滤波操作,再相加(记住还要加上人脸模板)。最大得分的位置即为检测到的人脸位置。

KNN & K折交叉验证

KNN的训练可以看作是确定最合适的k值的过程。首先我们拥有训练集和测试集,由于k值的确定因数据集、分类任务而异,它并没有统一的最佳值,因此需要在训练集上进行确定。如何做呢?这里引入了验证集的概念。之后使用K折交叉验证,在训练集上就可以确定最佳K值,再将此值apply到测试集上即可。

hw7——光流

光流法所针对的对象为一帧帧连续图像frame,即处理对象为视频

步骤

假设我们有两帧连续图像frame0和frame1

  1. 在第一帧图像上进行harris角点检测,得到特征点keypoints

  2. 在这里插入图片描述

对于每一个特征点,在其所在窗口内计算以上矩阵A和b(It由第二章图片减第一张图片得到),v向量是该特征点处待求光流.

  1. 利用最小二乘法,计算向量v. 即可在每一个特征点上求得(窗口内大小方向一致的)光流.

之后,可以在仅计算了frame0特征点的基础上追踪后面多帧的相同特征点了:compute_error()函数每次会比较此帧此特征点附近窗口内两patch之间的距离(需要先进行归一化),如果距离过大,则放弃追踪该特征点.

弊端:One limitation of the naive Lucas-Kanade method is that it cannot track large motions between frames.

改进:基于迭代的Lucas-Kanade方法

  • 初始化光流:

v = [ 0 0 ] v= \begin{bmatrix} 0\\0 \end{bmatrix} v=[00]

  • Compute spatial gradient matrix:

G = ∑ x = p x − w p x + w ∑ y = p y − w p y + w [ I x 2 ( x , y ) I x ( x , y ) I y ( x , y ) I x ( x , y ) I y ( x , y ) I y 2 ( x , y ) ] G=\sum_{x=p_x-w}^{p_x+w}\sum_{y=p_y-w}^{p_y+w} \begin{bmatrix} I_{x}^2(x,y) & I_{x}(x,y)I_{y}(x,y)\\ I_{x}(x,y)I_{y}(x,y) & I_{y}^2(x,y) \end{bmatrix} G=x=pxwpx+wy=pywpy+w[Ix2(x,y)Ix(x,y)Iy(x,y)Ix(x,y)Iy(x,y)Iy2(x,y)]

  • for k = 1 k=1 k=1 to K K K

    • Compute temporal difference: δ I k ( x , y ) = I ( x , y ) − J ( x + g x + v x , y + g y + v y ) \delta I_k(x, y) = I(x,y)-J(x+g_x+v_x, y+g_y+v_y) δIk(x,y)=I(x,y)J(x+gx+vx,y+gy+vy)

    • Compute image mismatch vector:
      b k = ∑ x = p x − w p x + w ∑ y = p y − w p y + w [ δ I k ( x , y ) I x ( x , y ) δ I k ( x , y ) I y ( x , y ) ] b_k=\sum_{x=p_x-w}^{p_x+w}\sum_{y=p_y-w}^{p_y+w} \begin{bmatrix} \delta I_k(x, y)I_x(x,y)\\ \delta I_k(x, y)I_y(x,y) \end{bmatrix} bk=x=pxwpx+wy=pywpy+w[δIk(x,y)Ix(x,y)δIk(x,y)Iy(x,y)]

    • Compute optical flow: v k = G − 1 b k v^k=G^{-1}b_k vk=G1bk

    • Update flow vector for next iteration: v : = v + v k v := v + v^k v:=v+vk

    • Return v v v

hw8

T_camera_from_world()
# 如何将世界中的坐标转换为camera中的坐标?即c=Tw
answer:hw8中,让相机和世界中某两个对应维度的坐标平面重合,我们以世界原点Ow和Oc作参考,如何将Ow(0,0,0)转为camera中的表示,就是将世界中坐标转换为camera中坐标的过程。
假设只需要两种变换:旋转+平移(先旋转,后平移!!!)
以camera坐标为参考,要把世界坐标系逆时针旋转多少度?
平移:可看作是将camera坐标系向世界坐标系平移,它需要平移多少?
实在不行的话,就代入矩阵T计算Tw是不是等于c
以上由于使用到了平移,因此需引入齐次坐标

新的正确理解:
以世界坐标为参考,将camera坐标逆时针旋转多少度(注意!!!)
之后再将camera坐标平移至原先世界坐标的原点

计算消失点:世界中三个相互正交的方向,每个方向有一组平行线。我们对它拍摄照片,转化到二维,计算每一组平行线在照片中的交点,即为消失点

计算光学中心:所谓光学中心,就是光经过该中心方向不会发生改变(不会有折射发生,可以联想初中知识,凸透镜的中心位置)。由三个消失点可以计算出光学中心的位置,它是二维的:三个消失点所组成三角形的垂心

计算焦距:在已知光学中心的情况下,焦距可以由两个消失点得到,有以下两种理解方式

①实际角度:它是三个消失点中三个垂线,每一个垂线被垂心分开的两条线段长度乘积的开方

②计算角度:给定两个消失点v1、v2和光学中心O,焦距可以由两向量(v1-O)和(v2-O)的内积的绝对值的开方得到

函数使用

axis
extend()
np.gradient()

np.stack()
np.vstack()
np.hstack()
np.dstack()

np.concatenate()

# 数学运算
np.linalg.inv()

np.pad()
np.flip()
np.insert()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值