集成开发环境,例如:Visual Studio Code;Pycharm等
操作系统给应用程序的调用接口
参考链接:https://www.cnblogs.com/marsggbo/p/11838823.html
context是一种上下文,关联对GPU的所有操作 context与一块显卡关联,一个显卡可以被多个context关联
每个线程都有一个栈结构储存context,栈顶是当前使用的context,对应有push、pop函数操作
context的栈,所有api都以当前context为操作目标
试想一下,如果执行任何操作你都需要传递一个device决定送到哪个设备执行,得多麻烦
由于高频操作,是一个线程基本固定访问一个显卡不变,且只使用一个context,很少会用到多context
CreateContext、PushCurrent、PopCurrent这种多context管理就显得麻烦,还得再简单
因此推出了cuDevicePrimaryCtxRetain,为设备关联主context,分配、释放、设置、栈都不用你管
primaryContext:给我设备id,给你context并设置好,此时一个显卡对应一个primary context
【注】:
不同线程,只要设备id一样,primary context就一样。context是线程安全的关键。
内存模型是CUDA中很重要的知识点,主要理解pinned memory、global memory、shared memory即可,其他不常用
对于整个Host Memory内存条而言,操作系统区分为两个大类(逻辑区分,物理上是同一个东西):
你可以理解为Page lock memory是vip房间,锁定给你一个人用。而Pageable memory是普通房间,在酒店房间不够的时候,选择性的把你的房间腾出来给其他人交换用,这就可以容纳更多人了。造成房间很多的假象,代价是性能降低
原则:
核函数里面,把blockDim、gridDim看作shape,把threadIdx、blockIdx看做index
则可以按照维度高低排序看待这个信息:
主要解决图像的缩放和平移,来处理目标检测中常见的预处理行为
测试时数据增强:指的是在推理(预测)阶段,将原始图片进行水平翻转、垂直翻转、对角线翻转、旋转角度等数据增强操作,得到多张图,分别进行推理,再对多个结果进行综合分析,得到最终输出结果。
非极大抑制:经典NMS最初第一次应用到目标检测中是在RCNN算法中,其实现严格按照搜索局部极大值,抑制非极大值元素的思想来实现的,具体的实现步骤如下:
当NMS的阈值设为0.2时:
python实现:
def nms(bounding_boxes, Nt):
if len(bounding_boxes) == 0:
return [], []
bboxes = np.array(bounding_boxes)
# 计算 n 个候选框的面积大小
x1 = bboxes[:, 0]
y1 = bboxes[:, 1]
x2 = bboxes[:, 2]
y2 = bboxes[:, 3]
scores = bboxes[:, 4]
areas = (x2 - x1 + 1) * (y2 - y1 + 1)
# 对置信度进行排序, 获取排序后的下标序号, argsort 默认从小到大排序
order = np.argsort(scores)
picked_boxes = [] # 返回值
while order.size > 0:
# 将当前置信度最大的框加入返回值列表中
index = order[-1]
picked_boxes.append(bounding_boxes[index])
# 获取当前置信度最大的候选框与其他任意候选框的相交面积
x11 = np.maximum(x1[index], x1[order[:-1]])
y11 = np.maximum(y1[index], y1[order[:-1]])
x22 = np.minimum(x2[index], x2[order[:-1]])
y22 = np.minimum(y2[index], y2[order[:-1]])
w = np.maximum(0.0, x22 - x11 + 1)
h = np.maximum(0.0, y22 - y11 + 1)
intersection = w * h
# 利用相交的面积和两个框自身的面积计算框的交并比, 将交并比大于阈值的框删除
ious = intersection / (areas[index] + areas[order[:-1]] - intersection)
left = np.where(ious < Nt)
order = order[left]
return picked_boxes
经典NMS算法存在着一些问题:对于重叠物体无法很好的检测。经典NMS算法的做法是直接删除Iou大于阈值的Bounding box;而Soft-NMS则是使用一个基于Iou的衰减函数,降低Iou大于阈值Nt的Bounding box的置信度,IoU越大,衰减程度越大。
python代码
def soft_nms(bboxes, Nt=0.3, sigma2=0.5, score_thresh=0.3, method=2):
# 在 bboxes 之后添加对于的下标[0, 1, 2...], 最终 bboxes 的 shape 为 [n, 5], 前四个为坐标, 后一个为下标
res_bboxes = deepcopy(bboxes)
N = bboxes.shape[0] # 总的 box 的数量
indexes = np.array([np.arange(N)]) # 下标: 0, 1, 2, ..., n-1
bboxes = np.concatenate((bboxes, indexes.T), axis=1) # concatenate 之后, bboxes 的操作不会对外部变量产生影响
# 计算每个 box 的面积
x1 = bboxes[:, 0]
y1 = bboxes[:, 1]
x2 = bboxes[:, 2]
y2 = bboxes[:, 3]
scores = bboxes[:, 4]
areas = (x2 - x1 + 1) * (y2 - y1 + 1)
for i in range(N):
# 找出 i 后面的最大 score 及其下标
pos = i + 1
if i != N - 1:
maxscore = np.max(scores[pos:], axis=0)
maxpos = np.argmax(scores[pos:], axis=0)
else:
maxscore = scores[-1]
maxpos = 0
# 如果当前 i 的得分小于后面的最大 score, 则与之交换, 确保 i 上的 score 最大
if scores[i] < maxscore:
bboxes[[i, maxpos + i + 1]] = bboxes[[maxpos + i + 1, i]]
scores[[i, maxpos + i + 1]] = scores[[maxpos + i + 1, i]]
areas[[i, maxpos + i + 1]] = areas[[maxpos + i + 1, i]]
# IoU calculate
xx1 = np.maximum(bboxes[i, 0], bboxes[pos:, 0])
yy1 = np.maximum(bboxes[i, 1], bboxes[pos:, 1])
xx2 = np.minimum(bboxes[i, 2], bboxes[pos:, 2])
yy2 = np.minimum(bboxes[i, 3], bboxes[pos:, 3])
w = np.maximum(0.0, xx2 - xx1 + 1)
h = np.maximum(0.0, yy2 - yy1 + 1)
intersection = w * h
iou = intersection / (areas[i] + areas[pos:] - intersection)
# Three methods: 1.linear 2.gaussian 3.original NMS
if method == 1: # linear
weight = np.ones(iou.shape)
weight[iou > Nt] = weight[iou > Nt] - iou[iou > Nt]
elif method == 2: # gaussian
weight = np.exp(-(iou * iou) / sigma2)
else: # original NMS
weight = np.ones(iou.shape)
weight[iou > Nt] = 0
scores[pos:] = weight * scores[pos:]
# select the boxes and keep the corresponding indexes
inds = bboxes[:, 5][scores > score_thresh]
keep = inds.astype(int)
return res_bboxes[keep]
加权框融合:假设,我们已经绑定了来自N个不同模型的相同图像的框预测。或者,我们对相同图像的原始和增强版本(即垂直/水平反射,数据增强)有相同模型的N个预测)。
参考链接🔗https://ethanli.blog.csdn.net/article/details/83056042
摄影测量的完整流程如下图所示:
立体匹配(Stereo Matching)的目标是从不同视点图像中找到匹配的对应点,从而从二维图像中恢复三维信息,其用处不只是用于摄影测量中所涉及的生成DSM/TDOM、Mesh/Model,还有三维环境感知与建模、机器人导航、物体跟踪与检测等,是摄影测量与计算视觉领域非常重要的一个热点研究方向。
全局和半全局的算法都源于:Markov Random Field
立体视觉入门资料阅读🔗:http://vision.deis.unibo.it/~smatt/Seminars/StereoVision.pdf
视差
d
d
d 等于同名点对在左视图的列坐标减去在右视图上的列坐标,是像素单位,立体视觉里,视差概念在极线校正后的像对里使用。
d
=
x
l
−
x
r
d=x_l-x_r
d=xl−xr
视差图(disparity map)
视差图指存储立体校正后单视图所有像素视差值的二维图像。
深度 D D D等于像素在该视图相机坐标系下 Z Z Z坐标,是空间单位。深度并不特在校正后的图像对里使用,而是任意图像都可获取深度图。
深度图(depth map)
深度图指存储单视图所有像素的深度值的二维图像,是空间单位,比如毫米。
点云指三维空间的三维点集合,坐标属性 ( X , Y , Z ) (X , Y , Z ) (X,Y,Z),法线属性 ( N x , N y , N z ) (N_x , N_y , N_z) (Nx,Ny,Nz)(可选) 颜色属性 ( R , G , B ) (R,G,B) (R,G,B)(可选)
总结如下:
立体匹配一般是指逐像素的稠密匹配,这意味着每个像素都会得到一个视差值(包括无效值),如何存储这些视差值呢,显然以二维图的方式存储是很合适的,最大的两点优势是一方面可以通过像素坐标快速的在二维图中找到对应位置的视差值,而且和图像一样是有序的,邻域检索、视差滤波等将会变得非常方便;另一方面是可以直观的通过观察视差图和原图的对比,对视差图的质量有初步的判定。
而深度图的意义则是以更少的存储空间、有序的表达图像匹配的三维成果。更少的存储空间是因为只保存了一个深度值,而不是三维点云的三个坐标值,而深度值是可以结合像素坐标计算三维点坐标值的。有序是因为深度图和原图像素是一一对应的,所以原图的邻域信息完全继承到了深度图里。
这就是视差图和深度图的意义,视差图是立体匹配算法的产出,而深度图则是立体匹配到点云生成的中间桥梁。
视差图和深度图中间,有着一对一的转换公式:
D
=
B
f
d
+
(
x
0
r
−
x
0
l
)
D = \frac{Bf}{d+(x_{0r}-x_{0l})}
D=d+(x0r−x0l)Bf其中,
D
D
D为深度,
d
d
d为视差,
B
B
B为基线长度,
f
f
f为焦距(像素单位)
x
0
r
x_{0r}
x0r和
x
0
l
x_{0l}
x0l分别为左右视图主点的列坐标。,另一个较为熟知的公式是
D
=
B
f
d
D = \frac{Bf}{d}
D=dBf这是在左右视图主点的列坐标相同的特殊情况,比如主点都在中心。
深度图计算相机坐标系下的点云,也有着简单的公式:
Z
=
D
Z=D
Z=D
X
=
D
(
x
−
x
0
l
)
f
X= \frac{D(x-x_{0l})}{f}
X=fD(x−x0l)
Y
=
D
(
y
−
y
0
l
)
f
Y= \frac{D(y-y_{0l})}{f}
Y=fD(y−y0l)其中,
x
x
x ,
y
y
y为像素的列坐标和行坐标,
x
0
l
x_{0l}
x0l和
y
0
l
y_{0l}
y0l为主点的像素坐标。
注[1]:视差图是如何储存?
通常而言,我们是把二维视差图以图像格式存储,常见的格式有png、tif、pfm等,但这些图像格式存储的数据类型是有区别的,其中png只能存储整数,而tif和pfm则可以存储小数。而显然准确的视差值必然是浮点型的小数,所以存储为tif和pfm可以原值无损存储,而存储为png必然会损失精度,所以有的代码比如opencv会把得到的浮点型视差值乘以16倍取整,存储到png里,这样存储视差值的精度变为1/16,对于这种情况我们在读取png后要先除以16才是真实视差值,且视差会有阶梯分层现象。那有同学就问,既然这样为什么要存储png呢?是因为目前主流的图像软件,不支持直接看浮点格式的tif和pfm,存储为png可以更好的观看视差图,当然要是实际生产使用,是必然不建议存储为png的,用来查看视差结果是可以的。还有人会直接把视差值拉伸或者压缩到0~255,存储到png或bmp等存储整数的格式中,这样的视差图只能用来观看视差效果,没有其他作用,比如我的代码里的存储方式。