superPoint学习

superpoint是用于提取特征点,主要使用CNN。

网络架构

superPoint学习
采用编码解码的方式,提取特征点和计算描述子实际是两个网络,编码部分共用一个网络(就是简单的卷积池化,三次池化后,将图片分辨率降为H/8 * W/8,通道数为128),之后各自使用自己的网络。

提取特征点

1.先用256个33的卷积核将输入升维到H/8 * W/8 * 256,再用65个11的卷积核降维成H/8 * W/8 * 65.这里的思想:我们要提取特征点,是要将feature_map还原到HW的分辨率才可以提取,也就是前面编码后面就要解码,一般网络在后面解码会使用上采样或者反卷积,但计算量巨大,还会带来checkerboard artifacts,作者这里使用了sub-pixel convolution。
superPoint学习
比如我想将图片由H/8 * W/8变成H
W,那么我先卷积让它变成H/8 * W/8 * 64,再把这64个通道组合拼接成一个通道的H*W大图。
这是一种抽样的反思想,如果把一张x3的大图,每隔三个点抽样一个,那就会得到9张低分辨率的图像。于是,如果我们可以通过CNN来获得9张符合分布的低分辨率图像,那么就可以组成一张高分辨率的大图。
为啥使用65个通道?The 65
channels correspond to local, non-overlapping 8 × 8 grid
regions of pixels plus an extra “no interest point” dustbin.
After a channel-wise softmax, the dustbin dimension is re-
moved and a R H c ×W c ×64 ⇒ R H×W reshape is performed 我感觉作者认为有64种不同的特征,再加上一个没有特征。(卷积就是把图片里符合这个卷积核特征的地方突出出来)。最后丢掉这个没有特征的,代码里直接是把第65个通道剔除了。我也没有特别理解,感觉可以不需要啊。

计算描述子

同样的,此处也是一个解码器。先学习半稠密的描述子(不使用稠密的方式是为了减少计算量和内存),然后进行双三次插值算法(bicubic interpolation)得到完整描述子,最后再使用L2标准化(L2-normalizes)得到单位长度的描述。
后半部分代码解读

 # Compute the dense keypoint scores
        cPa = self.relu(self.convPa(x))  
        scores = self.convPb(cPa)    #[1, 65, 50, 80]
        scores = torch.nn.functional.softmax(scores, 1)[:, :-1] #[1, 64, 50, 80] 直接把65维的倒数第一维剔除了
        b, _, h, w = scores.shape    
        scores = scores.permute(0, 2, 3, 1).reshape(b, h, w, 8, 8) #[1, 50, 80, 8, 8]
        scores = scores.permute(0, 1, 3, 2, 4).reshape(b, h*8, w*8) #[1, 400, 640] 每个像素点都有一个得分
        scores = simple_nms(scores, self.config['nms_radius']) #[1, 400, 640] #除掉相邻的点
        print(scores.shape)
        # Extract keypoints
        keypoints = [
            torch.nonzero(s > self.config['keypoint_threshold']) #nonzero返回一个包含输入Input中非0元素索引的张量
            for s in scores]
        scores = [s[tuple(k.t())] for s, k in zip(scores, keypoints)] #把keypoints索引处的score拿出来
        print(len(scores))
        # Discard keypoints near the image borders
        keypoints, scores = list(zip(*[
            remove_borders(k, s, self.config['remove_borders'], h*8, w*8)
            for k, s in zip(keypoints, scores)]))
        
        # Keep the k keypoints with highest score
        if self.config['max_keypoints'] >= 0:          #把得分最高的前max_keypoints取出来
            keypoints, scores = list(zip(*[
                top_k_keypoints(k, s, self.config['max_keypoints'])
                for k, s in zip(keypoints, scores)]))

        # Convert (h, w) to (x, y)
        print(len(keypoints))
        keypoints = [torch.flip(k, [1]).float() for k in keypoints] #这里就是把keypoint的坐标(a,b)变为(b,a)
        print(len(keypoints))   #[tensor([[ 41.,   8.],[109.,   8.],..,[217.,   8.]])] list长度为1
        # Compute the dense descriptors
        cDa = self.relu(self.convDa(x))
        descriptors = self.convDb(cDa)
        descriptors = torch.nn.functional.normalize(descriptors, p=2, dim=1)
        
        # Extract descriptors
        descriptors = [sample_descriptors(k[None], d[None], 8)[0]
                       for k, d in zip(keypoints, descriptors)]

        return {
            'keypoints': keypoints,
            'scores': scores,
            'descriptors': descriptors,
        } 
    

superPoint学习

上一篇:欧盟项目--税务系统ELSTER连接


下一篇:水仙花数()