文章目录

脉冲式激光测距由激光发射器发射出的激光经被测量物体的反射后又被接收。测距仪同时记录激光往返的时间。光速和往返时间的乘积的一半就是测距仪和被测量物体之间的距离,设备记录本身在水平和垂直方向的旋转角度,再通过软件,计算出三维数据。

相位式激光测距是通过测量调制的激光信号在待测距离上往返传播所形成的相位移,间接测出激光传播时间(利用波长和频率),再根据激光传播速度,求出待测距离。

由N NN个D DD维的点组成,当这个D = 3 D=3D=3的时候一般代表着( x , y , z ) (x,y,z)(x,y,z)的坐标,当然也可以包括一些法向量、强度等别的特征。这是今天主要讲述的数据类型。

点云应用方向:
机器人、自动驾驶
消费类电子产品

点云的分类是将点云分类到不同的点云集。同一个点云集具有相似或相同的属性,例如地面、树木、人等;点云分割是根据空间、几何和纹理等特征点进行划分,同一划分内的点云拥有相似的特征。
基于半径选择局部区域,针对得到的每个区域进行特征提取,关键核心原理:

def farthest_point_sample(xyz, npoint):
"""
Input:
xyz: pointcloud data, [B, N, 3]
npoint: number of samples
Return:
centroids: sampled pointcloud index, [B, npoint]
"""
device = xyz.device
B, N, C = xyz.shape
centroids = torch.zeros(B, npoint, dtype=torch.long).to(device)#8*512
distance = torch.ones(B, N).to(device) * 1e10 #8*1024
farthest = torch.randint(0, N, (B,), dtype=torch.long).to(device)#batch里每个样本随机初始化一个最远点的索引
batch_indices = torch.arange(B, dtype=torch.long).to(device)
for i in range(npoint):
centroids[:, i] = farthest #第一个采样点选随机初始化的索引
centroid = xyz[batch_indices, farthest, :].view(B, 1, 3)#得到当前采样点的坐标 B*3
dist = torch.sum((xyz - centroid) ** 2, -1)#计算当前采样点与其他点的距离
mask = dist < distance#选择距离最近的来更新距离(更新维护这个表)
distance[mask] = dist[mask]#
farthest = torch.max(distance, -1)[1]#重新计算得到最远点索引(在更新的表中选择距离最大的那个点)
return centroids
def query_ball_point(radius, nsample, xyz, new_xyz):
"""
Input:
radius: local region radius
nsample: max sample number in local region
xyz: all points, [B, N, 3]
new_xyz: query points, [B, S, 3]
Return:
group_idx: grouped points index, [B, S, nsample]
"""
device = xyz.device
B, N, C = xyz.shape
_, S, _ = new_xyz.shape
group_idx = torch.arange(N, dtype=torch.long).to(device).view(1, 1, N).repeat([B, S, 1])
sqrdists = square_distance(new_xyz, xyz)#得到B N M (就是N个点中每一个和M中每一个的欧氏距离)
group_idx[sqrdists > radius ** 2] = N #找到距离大于给定半径的设置成一个N值(1024)索引
group_idx = group_idx.sort(dim=-1)[0][:, :, :nsample]#做升序排序,后面的都是大的值(1024)
group_first = group_idx[:, :, 0].view(B, S, 1).repeat([1, 1, nsample])#如果半径内的点没那么多,就直接用第一个点来代替了。。。
mask = group_idx == N
group_idx[mask] = group_first[mask]
return group_idx
特征提取代码实现如下:
def forward(self, xyz, points):
"""
Input:
xyz: input points position data, [B, C, N]
points: input points data, [B, D, N]
Return:
new_xyz: sampled points position data, [B, C, S]
new_points_concat: sample points feature data, [B, D', S]
"""
xyz = xyz.permute(0, 2, 1) #就是坐标点位置特征
print(xyz.shape)
if points is not None:
points = points.permute(0, 2, 1) ##就是额外提取的特征,第一次的时候就是那个法向量特征
print(points.shape)
B, N, C = xyz.shape
S = self.npoint
new_xyz = index_points(xyz, farthest_point_sample(xyz, S))
print(new_xyz.shape)
new_points_list = []
for i, radius in enumerate(self.radius_list):
K = self.nsample_list[i]
group_idx = query_ball_point(radius, K, xyz, new_xyz)#返回的是索引
grouped_xyz = index_points(xyz, group_idx)#得到各个组中实际点
grouped_xyz -= new_xyz.view(B, S, 1, C)#去mean new_xyz相当于簇的中心点
if points is not None:
grouped_points = index_points(points, group_idx)
grouped_points = torch.cat([grouped_points, grouped_xyz], dim=-1)
print(grouped_points.shape)
else:
grouped_points = grouped_xyz
grouped_points = grouped_points.permute(0, 3, 2, 1) # [B, D, K, S]
print(grouped_points.shape)
for j in range(len(self.conv_blocks[i])):
conv = self.conv_blocks[i][j]
bn = self.bn_blocks[i][j]
grouped_points = F.relu(bn(conv(grouped_points)))
print(grouped_points.shape)
new_points = torch.max(grouped_points, 2)[0] # [B, D', S] 就是pointnet里的maxpool操作
print(new_points.shape)
new_points_list.append(new_points)
new_xyz = new_xyz.permute(0, 2, 1)
new_points_concat = torch.cat(new_points_list, dim=1)
print(new_points_concat.shape)
return new_xyz, new_points_concat


pointnet得到最终整体特征,再进行分割


点云补全就是希望基于观察到的残缺不全的点云生成完整的 3D 点云。由于扫描或者距离的原因导致点云局部缺失,对其进行补全,传统算法可能会补不完整,也可能会补的过于完整,今天这里要讲的是PF-Net: Point Fractal Network for 3D Point Cloud Completion,整体网络模型:

关键核心:


PF-Net特征提取代码实现如下:
def forward(self,x):
print(x.shape)
x = torch.unsqueeze(x,1)
print(x.shape)
x = F.relu(self.bn1(self.conv1(x)))
print(x.shape)
x = F.relu(self.bn2(self.conv2(x)))
print(x.shape)
x_128 = F.relu(self.bn3(self.conv3(x)))
print(x_128.shape)
x_256 = F.relu(self.bn4(self.conv4(x_128)))
x_512 = F.relu(self.bn5(self.conv5(x_256)))
x_1024 = F.relu(self.bn6(self.conv6(x_512)))
print(x_1024.shape)
x_128 = torch.squeeze(self.maxpool(x_128),2)
print(x_128.shape)
x_256 = torch.squeeze(self.maxpool(x_256),2)
x_512 = torch.squeeze(self.maxpool(x_512),2)
x_1024 = torch.squeeze(self.maxpool(x_1024),2)
print(x_1024.shape)
L = [x_1024,x_512,x_256,x_128]
x = torch.cat(L,1)
print(x.shape)
return x

PF-Net分层预测代码实现如下:
def forward(self,x):
print(np.array(x).shape)
x = self.latentfeature(x)
print(x.shape)
x_1 = F.relu(self.fc1(x)) #1024
print(x_1.shape)
x_2 = F.relu(self.fc2(x_1)) #512
print(x_2.shape)
x_3 = F.relu(self.fc3(x_2)) #256
print(x_3.shape)
pc1_feat = self.fc3_1(x_3)
print(pc1_feat.shape)
pc1_xyz = pc1_feat.reshape(-1,64,3) #64x3 center1
print(pc1_xyz.shape)
pc2_feat = F.relu(self.fc2_1(x_2))
print(pc2_feat.shape)
pc2_feat = pc2_feat.reshape(-1,128,64)
print(pc2_feat.shape)
pc2_xyz =self.conv2_1(pc2_feat) #6x64 center2
print(pc2_xyz.shape)
pc3_feat = F.relu(self.fc1_1(x_1))
print(pc3_feat.shape)
pc3_feat = pc3_feat.reshape(-1,512,128)
print(pc3_feat.shape)
pc3_feat = F.relu(self.conv1_1(pc3_feat))
print(pc3_feat.shape)
pc3_feat = F.relu(self.conv1_2(pc3_feat))
print(pc3_feat.shape)
pc3_xyz = self.conv1_3(pc3_feat) #12x128 fine
print(pc3_xyz.shape)
pc1_xyz_expand = torch.unsqueeze(pc1_xyz,2)
print(pc1_xyz_expand.shape)
pc2_xyz = pc2_xyz.transpose(1,2)
print(pc2_xyz.shape)
pc2_xyz = pc2_xyz.reshape(-1,64,2,3)
print(pc2_xyz.shape)
pc2_xyz = pc1_xyz_expand+pc2_xyz
print(pc2_xyz.shape)
pc2_xyz = pc2_xyz.reshape(-1,128,3)
print(pc2_xyz.shape)
pc2_xyz_expand = torch.unsqueeze(pc2_xyz,2)
print(pc2_xyz_expand.shape)
pc3_xyz = pc3_xyz.transpose(1,2)
print(pc3_xyz.shape)
pc3_xyz = pc3_xyz.reshape(-1,128,int(self.crop_point_num/128),3)
print(pc3_xyz.shape)
pc3_xyz = pc2_xyz_expand+pc3_xyz
print(pc3_xyz.shape)
pc3_xyz = pc3_xyz.reshape(-1,self.crop_point_num,3)
print(pc3_xyz.shape)
return pc1_xyz,pc2_xyz,pc3_xyz #center1 ,center2 ,fine


import math
r11 = 0 * math.log(0.8707) + (1-0) * math.log((1 - 0.8707))
r12 = 1 * math.log(0.7517) + (1-1) * math.log((1 - 0.7517))
r13 = 1 * math.log(0.8162) + (1-1) * math.log((1 - 0.8162))
r21 = 1 * math.log(0.3411) + (1-1) * math.log((1 - 0.3411))
r22 = 1 * math.log(0.4872) + (1-1) * math.log((1 - 0.4872))
r23 = 1 * math.log(0.6815) + (1-1) * math.log((1 - 0.6815))
r31 = 0 * math.log(0.4847) + (1-0) * math.log((1 - 0.4847))
r32 = 0 * math.log(0.6589) + (1-0) * math.log((1 - 0.6589))
r33 = 0 * math.log(0.5273) + (1-0) * math.log((1 - 0.5273))
r1 = -(r11 + r12 + r13) / 3
#0.8447112733378236
r2 = -(r21 + r22 + r23) / 3
#0.7260397266631787
r3 = -(r31 + r32 + r33) / 3
#0.8292933181294807
bceloss = (r1 + r2 + r3) / 3
print(bceloss)
判别模块代码实现如下:
def forward(self, x):
x = F.relu(self.bn1(self.conv1(x)))
x_64 = F.relu(self.bn2(self.conv2(x)))
x_128 = F.relu(self.bn3(self.conv3(x_64)))
x_256 = F.relu(self.bn4(self.conv4(x_128)))
x_64 = torch.squeeze(self.maxpool(x_64))
x_128 = torch.squeeze(self.maxpool(x_128))
x_256 = torch.squeeze(self.maxpool(x_256))
Layers = [x_256,x_128,x_64]
x = torch.cat(Layers,1)
x = F.relu(self.bn_1(self.fc1(x)))
x = F.relu(self.bn_2(self.fc2(x)))
x = F.relu(self.bn_3(self.fc3(x)))
x = self.fc4(x)
return x
点云配准实际上可以理解为:通过计算得到完美的坐标变换,将处于不同视角下的点云数据经过旋转平移等刚性变换统一整合到指定坐标系之下的过程。配准应用是一个基础技术,下游任务很多

传统算法代表:ICP,RPM等,涉及很多经验参数选择,今天这里要讲的是RPM-Net: Robust Point Matching using Learned Features,一条龙服务得到变换矩阵,效果对比:

关键核心:

def forward(self, x):
""" Returns alpha, beta, and gating_weights (if needed)
Args:
x: List containing two point clouds, x[0] = src (B, J, 3), x[1] = ref (B, K, 3)
Returns:
beta, alpha, weightings
"""
src_padded = F.pad(x[0], (0, 1), mode='constant', value=0)
ref_padded = F.pad(x[1], (0, 1), mode='constant', value=1)
concatenated = torch.cat([src_padded, ref_padded], dim=1)
print(concatenated.shape)
print(concatenated.permute(0, 2, 1).shape)
prepool_feat = self.prepool(concatenated.permute(0, 2, 1))
print(prepool_feat.shape)
pooled = torch.flatten(self.pooling(prepool_feat), start_dim=-2)
print(pooled.shape)
raw_weights = self.postpool(pooled)
print(raw_weights.shape)
beta = F.softplus(raw_weights[:, 0])
alpha = F.softplus(raw_weights[:, 1])
return beta, alpha
Feature Extraction(B)模块代码实现如下:
def sample_and_group_multi(npoint: int, radius: float, nsample: int, xyz: torch.Tensor, normals: torch.Tensor,
returnfps: bool = False):
"""Sample and group for xyz, dxyz and ppf features
Args:
npoint(int): Number of clusters (equivalently, keypoints) to sample.
Set to negative to compute for all points
radius(int): Radius of cluster for computing local features
nsample: Maximum number of points to consider per cluster
xyz: XYZ coordinates of the points
normals: Corresponding normals for the points (required for ppf computation)
returnfps: Whether to return indices of FPS points and their neighborhood
Returns:
Dictionary containing the following fields ['xyz', 'dxyz', 'ppf'].
If returnfps is True, also returns: grouped_xyz, fps_idx
"""
B, N, C = xyz.shape
if npoint > 0:
S = npoint
fps_idx = farthest_point_sample(xyz, npoint) # [B, npoint, C]
new_xyz = index_points(xyz, fps_idx)
nr = index_points(normals, fps_idx)[:, :, None, :]
else:
S = xyz.shape[1]
fps_idx = torch.arange(0, xyz.shape[1])[None, ...].repeat(xyz.shape[0], 1).to(xyz.device)
new_xyz = xyz
nr = normals[:, :, None, :]
idx = query_ball_point(radius, nsample, xyz, new_xyz, fps_idx) # (B, npoint, nsample)
grouped_xyz = index_points(xyz, idx) # (B, npoint, nsample, C)
print(grouped_xyz.shape)
d = grouped_xyz - new_xyz.view(B, S, 1, C) # d = p_r - p_i (B, npoint, nsample, 3)
ni = index_points(normals, idx)
print(ni.shape)
print(nr.shape)
print(d.shape)
nr_d = angle(nr, d)
print(nr_d.shape)
ni_d = angle(ni, d)
print(ni_d.shape)
nr_ni = angle(nr, ni)
print(nr_ni.shape)
d_norm = torch.norm(d, dim=-1)
xyz_feat = d # (B, npoint, n_sample, 3)
ppf_feat = torch.stack([nr_d, ni_d, nr_ni, d_norm], dim=-1) # (B, npoint, n_sample, 4)
print(ppf_feat.shape)
if returnfps:
return {'xyz': new_xyz, 'dxyz': xyz_feat, 'ppf': ppf_feat}, grouped_xyz, fps_idx
else:
return {'xyz': new_xyz, 'dxyz': xyz_feat, 'ppf': ppf_feat}
如果需要本文完整代码,以上算法论文或者点云数据资源的小伙伴可以私信我哦!
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
我正在尝试为我的iOS应用程序设置cocoapods但是当我执行命令时:sudogemupdate--system我收到错误消息:当前已安装最新版本。中止。当我进入cocoapods的下一步时:sudogeminstallcocoapods我在MacOS10.8.5上遇到错误:ERROR:Errorinstallingcocoapods:cocoapods-trunkrequiresRubyversion>=2.0.0.我在MacOS10.9.4上尝试了同样的操作,但出现错误:ERROR:Couldnotfindavalidgem'cocoapods'(>=0),hereiswhy:U
这太简单了,太荒谬了,我在任何地方都找不到关于它的任何信息,包括API文档和Rails源代码:我有一个:belongs_to关联,我开始理解当您没有关联时您在Controller中调用的正常模型方法与您有关联时调用的方法略有不同。例如,我的关联在创建Controller操作时运行良好:@user=current_user@building=Building.new(params[:building])respond_todo|format|if@user.buildings.create(params[:building])#etcetera但我找不到关于更新如何工作的文档:@user
升级到OSXYosemite后,我现有的pow.cx安装不起作用。升级到最新的pow.cx无效。通过事件监视器重新启动它也没有成功。 最佳答案 卸载(!)并重新安装解决了这个问题。curlget.pow.cx/uninstall.sh|shcurlget.pow.cx|sh 关于ruby-on-rails-OSXYosemite更新破坏了pow.cx,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/q
我们在Ubuntu14.04和Gitlab9.3.7上运行,运行良好。我们正在尝试更新到Gitlabv9.3.8的最新安全补丁,但它给我们这个错误:Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension.currentdirectory:/home/git/gitlab/vendor/bundle/ruby/2.3.0/gems/re2-1.0.0/ext/re2/usr/local/bin/ruby-r./siteconf20170720-19622-15i0edf.rbextconf.rbcheckingformain(
我遇到了以下问题。我有一个名为user的模型,它有一个名为activated的列。我试图通过激活的方法更新该值?但它给我错误:验证失败:密码不能为空,密码太短(最少6个字符)这对我来说没有意义,因为我没有接触密码字段!我只想更新激活的列。我把我认为相关的代码放在这里,但如果你认为你需要更多,请问:)非常感谢您!型号:attr_accessor:passwordattr_accessible:name,:email,:password,:password_confirmation,:activatedhas_many:sucu_votesemail_regex=/\A[\w+\-.]+@
当且仅当模型存在时,我才尝试更新模型的值。如果没有,我什么都不做。搜索似乎只返回更新或创建问题/答案,但我不想创建。我知道我可以用一个简单的方法来做到这一点:found=Model.find_by_id(id)iffoundupdatestuffend但是,我觉得有一种方法可以在一次调用中完成此操作,而无需分配任何临时本地值或执行if。如果记录不存在,我该如何编写一个Rails调用来更新记录而不出现嘈杂错误?最新的Rails3.x 最佳答案 您可以使用try在对find_by_id或where的结果调用update_attribut
我有一个允许更新用户记录的表单。它包含:password和:password_confirmation字段,但我不希望在数据库中已存储加密密码时对它们运行验证。View文件中的字段:'ConfirmPassword'%>在互联网上搜索时,我发现了这段代码,我认为它是针对以前版本的Ruby/Rails的。(我会把它放在我的用户模型中。)validates_presence_of:password,:on=>create由于我的用户模型中密码验证的语法不同(如下),我对我需要的语法感到困惑。validates:password,:presence=>true,:confirmation=>