使用LoFTR模型进行图像配准、重叠区提取

news2025/2/25 15:51:19

LoFTR模型源自2021年CVPR提出的一篇论文LoFTR: Detector-Free Local Feature Matching with Transformers,其基于pytorch实现图像配准,与基于superpoint+superglue的方法不同,
是一个端到端的图像配准方法。与LoFTR官方库相关的有loftr2onnx库,整体来说loftr2onnx库使用更方便,效果更好。但loftr2onnx转出的onnx模型是有问题的,不能使用。

项目地址:https://github.com/zju3dv/LoFTR
项目地址2:https://github.com/oooooha/loftr2onnx
demo体验:https://huggingface.co/spaces/kornia/Kornia-LoFTR

1、web demo体验

访问 https://huggingface.co/spaces/kornia/Kornia-LoFTR

点配准的效果如下所示,可以看到与sp+sg方法相比,点对的平行关系直观上要好很多。
在这里插入图片描述

2、使用LoFTR项目

2.1 下载代码

打开https://github.com/zju3dv/LoFTR 下载代码
在这里插入图片描述

2.2 安装依赖项

安装项目使用:解压代码,然后在终端进入目录,执行pip install -r .\requirements.txt
在这里插入图片描述

2.3 下载模型

https://drive.google.com/drive/folders/1DOcOPZb3-5cWxLqn256AhwUVjBPifhuf 下载权重。如果需要训练,可以下载训练数据与从测试数据。
在这里插入图片描述
将权重的压缩文件解压后放到项目根目录下
在这里插入图片描述

2.4 初步使用

将 https://hpg123.blog.csdn.net/article/details/124824892 中章节3的代码(对应标题为 superpoint中read_img_as_tensor函数)保存为imgutils.py

from src.loftr import LoFTR, default_cfg
import torch
from imgutils import *
import time
# Initialize LoFTR
matcher = LoFTR(config=default_cfg)
matcher.load_state_dict(torch.load("weights/indoor_ds_new.ckpt")['state_dict'])
matcher = matcher.eval().cuda()

p1=r'C:\Users\hpg\Pictures\t1.jpg'
p2=r'C:\Users\hpg\Pictures\t2.jpg'
t1,im1=read_img_as_tensor(p1,(384,384))
t2,im2=read_img_as_tensor(p2,(384,384))
batch = {'image0': t1, 'image1': t2}
# Inference
with torch.no_grad():
    matcher(batch)    # 
    t0=time.time()
    times=10
    for i in range(times):
        matcher(batch)
    rt1=time.time()-t0
    rt1=rt1/times
    mkpts0 = batch['mkpts0_f'].cpu().numpy()
    mkpts1 = batch['mkpts1_f'].cpu().numpy()
    mconf = batch['mconf'].cpu().numpy()
    print(f'运行时间:{rt1:.4f}',mkpts0.shape,mkpts1.shape,mconf)

代码运行效果如下所示,可以看到一个图片需要0.19s(笔记本,1060显卡),换成台式机3060显卡,预计在0.05s左右一张图

运行时间:0.1933 (32, 2) (32, 2) [0.22855578 0.21740437 0.34927088 0.28389925 0.27157754 0.26966828
 0.22636016 0.22058277 0.20475665 0.20878278 0.22838292 0.25448585
 0.27047077 0.34403533 0.22612476 0.2044811  0.26239234 0.32797554
 0.2263804  0.26544347 0.3401669  0.39336586 0.3473139  0.28230694
 0.23061718 0.23949552 0.46178365 0.3540019  0.5322925  0.27200237
 0.26731068 0.39827508]

3、使用loftr2onnx库进行配准

3.1 基本使用

也可以基于 https://github.com/oooooha/loftr2onnx 项目进行图像配准
在这里插入图片描述
使用代码如下


from loftr_wrapper import LoFTRWrapper as LoFTR
import torch
from imgutils import *
import time
# Initialize LoFTR
matcher = LoFTR()
matcher.load_state_dict(torch.load("weights/indoor_ds_new.ckpt")['state_dict'])
matcher = matcher.eval().cuda()

p1=r'C:\Users\hpg\Pictures\t1.jpg'
p2=r'C:\Users\hpg\Pictures\t2.jpg'
t1,im1=read_img_as_tensor(p1,(384,384))
t2,im2=read_img_as_tensor(p2,(384,384))
# Inference
with torch.no_grad():
    result=matcher(t1,t2)    # 
    t0=time.time()
    times=10
    for i in range(times):
        result=matcher(t1,t2)
    rt1=time.time()-t0
    rt1=rt1/times
    mkpts0 = result['keypoints0'].cpu().numpy()
    mkpts1 = result['keypoints1'].cpu().numpy()
    mconf = result['confidence'].cpu().numpy()
    print(f'运行时间:{rt1:.4f}',mkpts0.shape,mkpts1.shape,mconf)

代码输出如下所示,可以看到与LoFTR项目的输出有所差异

运行时间:0.1925 (212, 2) (212, 2) [0.4566688  0.53420454 0.5319168  0.5320238  0.46744433 0.4068214
 0.5363396  0.45674214 0.60001785 0.6576139  0.53006035 0.59590924
 0.5725811  0.5505655  0.44364485 0.40315574 0.4293331  0.5060973
 0.6550978  0.52451503 0.553644   0.63088214 0.6906601  0.61668074
 0.4543735  0.4138872  0.4332955  0.47855106 0.60533136 0.6735143
 0.7912271  0.7220486  0.75414115 0.75669855 0.60389113 0.40305066
 0.71130437 0.6583284  0.5403245  0.5433615  0.40149704 0.6673844
 0.4093839  0.5410701  0.51509964 0.42121148 0.68238974 0.55247396
 0.5116625  0.8369319  0.53321654 0.5323315  0.5779519  0.64705926
 0.43591025 0.40134645 0.4599252  0.46620858 0.6388375  0.8354758
 0.515318   0.6521981  0.54744494 0.64528877 0.7466613  0.6359517
 0.58179545 0.4587202  0.4856584  0.42029297 0.43322447 0.43220758
 0.6896481  0.79645556 0.5817581  0.75245494 0.5786756  0.7251559
 0.814531   0.49031648 0.46484298 0.54241467 0.5943087  0.7245115
 0.6457875  0.8097793  0.7199513  0.49220178 0.5443373  0.4086104
 0.5046131  0.7193697  0.6752727  0.41796637 0.5513792  0.7087418
 0.7779165  0.75016826 0.68525094 0.58962977 0.6315668  0.4913085
 0.56355244 0.41288543 0.52281946 0.42782715 0.43921712 0.5216018
 0.5566503  0.78442967 0.6013023  0.42023212 0.43102428 0.61564064
 0.40717542 0.49634054 0.45509326 0.4511342  0.41775596 0.55897176
 0.56803375 0.6018254  0.71239305 0.44001386 0.43651453 0.6947733
 0.8648205  0.4988858  0.40208712 0.71607304 0.9030141  0.5543826
 0.49472648 0.5359598  0.74733096 0.6617334  0.7066015  0.725677
 0.43446922 0.5126569  0.52367914 0.45096788 0.4248741  0.43285275
 0.723374   0.86523044 0.65740126 0.427191   0.4776224  0.4801826
 0.4530296  0.4275035  0.527438   0.52301216 0.58992577 0.41727343
 0.48609605 0.7365703  0.6339512  0.6379226  0.4489899  0.41325048
 0.5010124  0.49238032 0.57079905 0.62783945 0.5092921  0.5726387
 0.60590863 0.44714844 0.6284152  0.40801758 0.40126294 0.4221419
 0.52245826 0.70989937 0.49206337 0.553483   0.4956581  0.4180697
 0.6228596  0.6543849  0.7747963  0.61180156 0.60290194 0.5421194
 0.6149054  0.48783877 0.40048426 0.47044232 0.40145218 0.42359856
 0.68902797 0.44713116 0.84827214 0.48961237 0.6137104  0.7752426
 0.7184252  0.71058017 0.47483382 0.7151901  0.78853625 0.66988254
 0.7502565  0.42592585 0.49173304 0.4657402  0.59592575 0.42850277
 0.4645101  0.5070625 ]

3.2 差异分析

1、这主要是loftr2onnx项目通过loftr_wrapper对LoFTR的forward流程进行了调整。

#!/usr/bin/env python
import copy
import os
import sys
from typing import Any, Dict

import torch
from einops.einops import rearrange

_CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(_CURRENT_DIR, "LoFTR"))

from loftr import LoFTR, default_cfg

DEFAULT_CFG = copy.deepcopy(default_cfg)
DEFAULT_CFG["coarse"]["temp_bug_fix"] = True


class LoFTRWrapper(LoFTR):
    def __init__(
        self,
        config: Dict[str, Any] = DEFAULT_CFG,
    ):
        LoFTR.__init__(self, config)

    def forward(
        self,
        image0: torch.Tensor,
        image1: torch.Tensor,
    ) -> Dict[str, torch.Tensor]:
        data = {
            "image0": image0,
            "image1": image1,
        }
        del image0, image1

        data.update(
            {
                "bs": data["image0"].size(0),
                "hw0_i": data["image0"].shape[2:],
                "hw1_i": data["image1"].shape[2:],
            }
        )

        if data["hw0_i"] == data["hw1_i"]:  # faster & better BN convergence
            feats_c, feats_f = self.backbone(
                torch.cat([data["image0"], data["image1"]], dim=0)
            )
            (feat_c0, feat_c1), (feat_f0, feat_f1) = feats_c.split(
                data["bs"]
            ), feats_f.split(data["bs"])
        else:  # handle different input shapes
            (feat_c0, feat_f0), (feat_c1, feat_f1) = self.backbone(
                data["image0"]
            ), self.backbone(data["image1"])

        data.update(
            {
                "hw0_c": feat_c0.shape[2:],
                "hw1_c": feat_c1.shape[2:],
                "hw0_f": feat_f0.shape[2:],
                "hw1_f": feat_f1.shape[2:],
            }
        )

        # 2. coarse-level loftr module
        # add featmap with positional encoding, then flatten it to sequence [N, HW, C]
        feat_c0 = rearrange(self.pos_encoding(feat_c0), "n c h w -> n (h w) c")
        feat_c1 = rearrange(self.pos_encoding(feat_c1), "n c h w -> n (h w) c")

        mask_c0 = mask_c1 = None  # mask is useful in training
        if "mask0" in data:
            mask_c0, mask_c1 = data["mask0"].flatten(-2), data["mask1"].flatten(-2)
        feat_c0, feat_c1 = self.loftr_coarse(feat_c0, feat_c1, mask_c0, mask_c1)

        # 3. match coarse-level
        self.coarse_matching(feat_c0, feat_c1, data, mask_c0=mask_c0, mask_c1=mask_c1)

        # 4. fine-level refinement
        feat_f0_unfold, feat_f1_unfold = self.fine_preprocess(
            feat_f0, feat_f1, feat_c0, feat_c1, data
        )
        if feat_f0_unfold.size(0) != 0:  # at least one coarse level predicted
            feat_f0_unfold, feat_f1_unfold = self.loftr_fine(
                feat_f0_unfold, feat_f1_unfold
            )

        # 5. match fine-level
        self.fine_matching(feat_f0_unfold, feat_f1_unfold, data)

        rename_keys: Dict[str, str] = {
            "mkpts0_f": "keypoints0",
            "mkpts1_f": "keypoints1",
            "mconf": "confidence",
        }
        out: Dict[str, torch.Tensor] = {}
        for k, v in rename_keys.items():
            _d = data[k]
            if isinstance(_d, torch.Tensor):
                out[v] = _d
            else:
                raise TypeError(
                    f"Expected torch.Tensor for item `{k}`. Gotcha {type(_d)}"
                )
        del data

        return out

2、然后cfg或许有不同

loftr2onnx中的默认配置在loftr\utils\cvpr_ds_config.py中,如下所示。可以看到 _CN.MATCH_COARSE.THR与_CN.MATCH_COARSE.BORDER_RM 是做过修改的,与默认值不同

from yacs.config import CfgNode as CN


def lower_config(yacs_cfg):
    if not isinstance(yacs_cfg, CN):
        return yacs_cfg
    return {k.lower(): lower_config(v) for k, v in yacs_cfg.items()}


_CN = CN()
_CN.BACKBONE_TYPE = 'ResNetFPN'
_CN.RESOLUTION = (8, 2)  # options: [(8, 2), (16, 4)]
_CN.FINE_WINDOW_SIZE = 5  # window_size in fine_level, must be odd
_CN.FINE_CONCAT_COARSE_FEAT = True

# 1. LoFTR-backbone (local feature CNN) config
_CN.RESNETFPN = CN()
_CN.RESNETFPN.INITIAL_DIM = 128
_CN.RESNETFPN.BLOCK_DIMS = [128, 196, 256]  # s1, s2, s3

# 2. LoFTR-coarse module config
_CN.COARSE = CN()
_CN.COARSE.D_MODEL = 256
_CN.COARSE.D_FFN = 256
_CN.COARSE.NHEAD = 8
_CN.COARSE.LAYER_NAMES = ['self', 'cross'] * 4
_CN.COARSE.ATTENTION = 'linear'  # options: ['linear', 'full']
_CN.COARSE.TEMP_BUG_FIX = False

# 3. Coarse-Matching config
_CN.MATCH_COARSE = CN()
_CN.MATCH_COARSE.THR = 0.4  # thresh default=0.2
_CN.MATCH_COARSE.BORDER_RM = 4  # border default=2
_CN.MATCH_COARSE.MATCH_TYPE = 'dual_softmax'  # options: ['dual_softmax, 'sinkhorn']
_CN.MATCH_COARSE.DSMAX_TEMPERATURE = 0.1
_CN.MATCH_COARSE.SKH_ITERS = 3
_CN.MATCH_COARSE.SKH_INIT_BIN_SCORE = 1.0
_CN.MATCH_COARSE.SKH_PREFILTER = True
_CN.MATCH_COARSE.TRAIN_COARSE_PERCENT = 0.4  # training tricks: save GPU memory
_CN.MATCH_COARSE.TRAIN_PAD_NUM_GT_MIN = 200  # training tricks: avoid DDP deadlock

# 4. LoFTR-fine module config
_CN.FINE = CN()
_CN.FINE.D_MODEL = 128
_CN.FINE.D_FFN = 128
_CN.FINE.NHEAD = 8
_CN.FINE.LAYER_NAMES = ['self', 'cross'] * 1
_CN.FINE.ATTENTION = 'linear'

default_cfg = lower_config(_CN)

4、基于LoFTR提取重叠区域

4.1 使用LoFTR库

这里的imgutils 与前文说明的有细微区别,打开https://blog.csdn.net/a486259/article/details/124824892 将章节1的代码保存为imgutils.py即可

from src.loftr import LoFTR, default_cfg
import torch
from imgutils import *
import time
# Initialize LoFTR
matcher = LoFTR(config=default_cfg)
matcher.load_state_dict(torch.load("weights/indoor_ds_new.ckpt")['state_dict'])
matcher = matcher.eval().cuda()

p1=r'C:\Users\hpg\Pictures\t1.jpg'
p2=r'C:\Users\hpg\Pictures\t2.jpg'
t1,im1=read_img_as_tensor_gray(p1,(384,384))
t2,im2=read_img_as_tensor_gray(p2,(384,384))
batch = {'image0': t1, 'image1': t2}
# Inference
with torch.no_grad():
    t0=time.time()
    times=1
    for i in range(times):
        matcher(batch)
    rt1=time.time()-t0
    rt1=rt1/times
    mkpts0 = batch['mkpts0_f'].cpu().numpy()
    mkpts1 = batch['mkpts1_f'].cpu().numpy()
    confidence = batch['mconf'].cpu().numpy()
    print(f'运行时间:{rt1:.4f}',mkpts0.shape,mkpts1.shape)


import cv2 as cv
pt_num = mkpts0.shape[0]
im_dst,im_res=im1,im2
img = np.zeros((max(im_dst.shape[0], im_res.shape[0]), im_dst.shape[1]+im_res.shape[1]+10,3))
img[:,:im_res.shape[0],]=im_dst
img[:,-im_res.shape[0]:]=im_res
img=img.astype(np.uint8)
match_threshold=0.6
for i in range(0, pt_num):
    if (confidence[i] > match_threshold):
        pt0 = mkpts0[i].to('cpu').numpy().astype(np.int32)
        pt1 = mkpts1[i].to('cpu').numpy().astype(np.int32)
        #cv.circle(img, (pt0[0], pt0[1]), 1, (0, 0, 255), 2)
        #cv.circle(img, (pt1[0], pt1[1]+650), (0, 0, 255), 2)
        cv.line(img, pt0, (pt1[0]+im_res.shape[0], pt1[1]), (0, 255, 0), 1)
myimshow( img,size=12)

import cv2
def getGoodMatchPoint(mkpts0, mkpts1, confidence,  match_threshold:float=0.5):
    n = min(mkpts0.size(0), mkpts1.size(0))
    srcImage1_matchedKPs, srcImage2_matchedKPs=[],[]

    if (match_threshold > 1 or match_threshold < 0):
        print("match_threshold error!")

    for i in range(n):
        kp0 = mkpts0[i]
        kp1 = mkpts1[i]
    
        pt0=(kp0[0].item(),kp0[1].item());
        pt1=(kp1[0].item(),kp1[1].item());
        c = confidence[i].item();
        if (c > match_threshold):
            srcImage1_matchedKPs.append(pt0);
            srcImage2_matchedKPs.append(pt1);
    
    return np.array(srcImage1_matchedKPs),np.array(srcImage2_matchedKPs)
pts_src, pts_dst=getGoodMatchPoint(mkpts0, mkpts1, confidence)

h1, status = cv2.findHomography(pts_src, pts_dst, cv.RANSAC, 8)
im_out1 = cv2.warpPerspective(im_dst, h1, (im_dst.shape[1],im_dst.shape[0]))
im_out2 = cv2.warpPerspective(im_res, h1, (im_dst.shape[1],im_dst.shape[0]),16)
#这里 im_res和im_out1是严格配准的状态
myimshowsCL([im_dst,im_out1,im_res,im_out2],rows=2,cols=2, size=6)

在这里插入图片描述
代码运行报错,因为匹配到的点太少了,无法计算转化矩阵提取重叠区

4.2 使用loftr2onnx库

这里的imgutils 与前文说明的有细微区别,打开https://blog.csdn.net/a486259/article/details/124824892 将章节1的代码保存为imgutils.py即可

使用代码如下


from loftr_wrapper import LoFTRWrapper as LoFTR
import torch
from imgutils import *
import time
# Initialize LoFTR
matcher = LoFTR()
matcher.load_state_dict(torch.load("weights/indoor_ds_new.ckpt")['state_dict'])
matcher = matcher.eval().cuda()

p1=r'C:\Users\hpg\Pictures\t1.jpg'
p2=r'C:\Users\hpg\Pictures\t2.jpg'
t1,im1=read_img_as_tensor_gray(p1,(384,384))
t2,im2=read_img_as_tensor_gray(p2,(384,384))
# Inference
with torch.no_grad():
    #result=matcher(t1,t2)    # 
    t0=time.time()
    times=1
    for i in range(times):
        result=matcher(t1,t2)
    rt1=time.time()-t0
    rt1=rt1/times
    mkpts0 = result['keypoints0']#.cpu().numpy()
    mkpts1 = result['keypoints1']#.cpu().numpy()
    confidence = result['confidence']#.cpu().numpy()
    print(f'运行时间:{rt1:.4f}',mkpts0.shape,mkpts1.shape,confidence)

import cv2 as cv
pt_num = mkpts0.shape[0]
im_dst,im_res=im1,im2
img = np.zeros((max(im_dst.shape[0], im_res.shape[0]), im_dst.shape[1]+im_res.shape[1]+10,3))
img[:,:im_res.shape[0],]=im_dst
img[:,-im_res.shape[0]:]=im_res
img=img.astype(np.uint8)
match_threshold=0.01
for i in range(0, pt_num):
    if (confidence[i] > match_threshold):
        pt0 = mkpts0[i].to('cpu').numpy().astype(np.int32)
        pt1 = mkpts1[i].to('cpu').numpy().astype(np.int32)
        #cv.circle(img, (pt0[0], pt0[1]), 1, (0, 0, 255), 2)
        #cv.circle(img, (pt1[0], pt1[1]+650), (0, 0, 255), 2)
        cv.line(img, tuple(pt0.tolist()), (pt1[0]+im_res.shape[0], pt1[1]), (0, 255, 0), 1)
myimshow( img,size=12)

import cv2
def getGoodMatchPoint(mkpts0, mkpts1, confidence,  match_threshold:float=0.5):
    n = min(mkpts0.size(0), mkpts1.size(0))
    srcImage1_matchedKPs, srcImage2_matchedKPs=[],[]

    if (match_threshold > 1 or match_threshold < 0):
        print("match_threshold error!")

    for i in range(n):
        kp0 = mkpts0[i]
        kp1 = mkpts1[i]
    
        pt0=(kp0[0].item(),kp0[1].item());
        pt1=(kp1[0].item(),kp1[1].item());
        c = confidence[i].item();
        if (c > match_threshold):
            srcImage1_matchedKPs.append(pt0);
            srcImage2_matchedKPs.append(pt1);
    
    return np.array(srcImage1_matchedKPs),np.array(srcImage2_matchedKPs)
pts_src, pts_dst=getGoodMatchPoint(mkpts0, mkpts1, confidence)

h1, status = cv2.findHomography(pts_src, pts_dst, cv.RANSAC, 4)
# im_dst=im_dst.astype(np.float32)/255
# im_res=im_res.astype(np.float32)/255
print(im_dst.shape,im_dst.dtype,im_dst.max(),im_res.shape,im_res.dtype,im_res.max(),h1)
im_out1 = cv2.warpPerspective(im_dst, h1, (im_dst.shape[1],im_dst.shape[0]))
im_out2 = cv2.warpPerspective(im_res, h1, (im_dst.shape[1],im_dst.shape[0]),16)
#这里 im_res和im_out1是严格配准的状态
myimshowsCL([im_dst,im_out1,im_res,im_out2],rows=2,cols=2, size=6)

提取的点对关系如下所示
在这里插入图片描述
提取出的重叠区域
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1901897.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

推荐好玩的工具之OhMyPosh使用

解除禁止脚本 Set-ExecutionPolicy RemoteSigned 下载Oh My Posh winget install oh-my-posh 或者 Install-Module oh-my-posh -Scope AllUsers 下载Git提示 Install-Module posh-git -Scope CurrentUser 或者 Install-Module posh-git -Scope AllUser 下载命令提示 Install-Mo…

搜索旋转数组

题目链接 搜索旋转数组 题目描述 注意点 数组已被旋转过很多次数组元素原先是按升序排列的若有多个相同元素&#xff0c;返回索引值最小的一个 解答思路 首先需要知道的是&#xff0c;本题数组中的旋转多次只是将头部的某些元素移动到尾部&#xff0c;所以不论怎么旋转&am…

欢迎加入国家智能网联汽车创新中心OS开发训练营大家庭

欢迎加入国家智能网联汽车创新中心OS开发训练营大家庭。&#x1f680; 导学阶段启动 在正式开营之前&#xff0c;我们特别设置了导学阶段&#xff0c;旨在帮助大家更好地迎接颇具挑战性的项目实战。导学阶段包括一系列精心准备的视频课程和配套习题。github链接&#xff1a;htt…

20K Stars!一个轻量级的 JS 库

大家好,我是CodeQi! 一位热衷于技术分享的码仔。 Driver.js 是一个轻量级的 JavaScript 库,旨在帮助开发人员创建网站或应用程序的引导和教程。通过 Driver.js,您可以引导用户了解网站的各个功能和使用方式。 Driver.js 提供了高度可定制的功能,使其能够适应各种需求和…

Unity编辑器扩展之Inspector面板扩展

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity编辑器扩展之Inspector面板扩展 TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不断探索 TechX —— 心探索、心进取&#xff…

开关阀(4):对于客户技术要求信息的识别

1.阀门部分 2.执行器 行程时间的一般标准 The stroking times are applicable to throttling control valves and should not exceed 2 seconds/inch of valve diameter 3.附件 4.定位器

ubuntu设置开启自动挂载sftp

1. 前言 与其说 ubuntu 开启自动挂载 sftp, 更确切的说应该是 nautilus (ubuntu上默认的文件管理器) 开机自动挂载 sftp。 因为 这里即使选择永远记住&#xff0c;开机也不会自动挂载 sftp 2.设置方法 gnome-session-properties #开机只启动设置命令设置 gio mount sftp…

科普文:构建可扩展的微服务架构设计方案

前言 微服务架构是一种新兴的软件架构风格&#xff0c;它将单个应用程序拆分成多个小的服务&#xff0c;每个服务都运行在自己的进程中&#xff0c;这些服务通过网络进行通信。这种架构的优势在于它可以提高应用程序的可扩展性、可维护性和可靠性。 在传统的应用程序架构中&…

《昇思25天学习打卡营第13天|onereal》

今天学习的内容如下&#xff1a; DCGN生成漫画头像 在下面的教程中&#xff0c;我们将通过示例代码说明DCGAN网络如何设置网络、优化器、如何计算损失函数以及如何初始化模型权重。在本教程中&#xff0c;使用的动漫头像数据集共有70,171张动漫头像图片&#xff0c;图片大小均为…

Linux SSH服务介绍

1. 引言 在现代IT基础设施中&#xff0c;远程访问和管理服务器已成为日常运维工作的重要组成部分。Secure Shell (SSH) 是一种广泛使用的加密网络协议&#xff0c;允许在不安全的网络上安全地进行远程登录和其他网络服务。本文将详细介绍SSH服务的各个方面&#xff0c;包括其定…

String类对象比较:==和equals的具体细节

public class test {public static void main(String[] args) {String name1 "zzz";String name2 "zzz";String name3 new String("zzz");// hashCode() 方法&#xff1a;基于字符串的内容计算哈希值&#xff0c;因此内容相同的字符串对象其 …

anaconda中下载压缩包并用conda安装包

有时直接conda安装包时会出错&#xff1b;报错PackagesNotFoundError: The following packages are not available from current channels 比如 conda install -y bioconda::ucsc-gtftogenepred #直接安装报错 #直接下载压缩包安装https://blog.csdn.net/weixin_45552562/ar…

最新扣子(Coze)实战案例:使用扩图功能,让你的图任意变换,完全免费教程

&#x1f9d9;‍♂️ 大家好&#xff0c;我是斜杠君&#xff0c;手把手教你搭建扣子AI应用。 &#x1f4dc; 本教程是《AI应用开发系列教程之扣子(Coze)实战教程》&#xff0c;完全免费学习。 &#x1f440; 微信关注公从号&#xff1a;斜杠君&#xff0c;可获取完整版教程。&a…

电商视角如何理解动态IP与静态IP

在电子商务的蓬勃发展中&#xff0c;网络基础设施的稳定性和安全性是至关重要的。其中&#xff0c;IP地址作为网络设备间通信的基础&#xff0c;扮演着举足轻重的角色。从电商的视角出发&#xff0c;我们可以将动态IP和静态IP比作电商平台上不同类型的店铺安排&#xff0c;以此…

如何配置 PostgreSQL 以实现高可用性和故障转移?

文章目录 一、高可用性和故障转移的概念&#xff08;一&#xff09;数据复制&#xff08;二&#xff09;监控和检测&#xff08;三&#xff09;快速切换 二、实现高可用性和故障转移的技术方案&#xff08;一&#xff09;流复制&#xff08;Streaming Replication&#xff09;&…

二叉树中的前序、中序、后续遍历(C语言)

目录 前序遍历概念代码递归分解图 中序遍历概念代码 后序遍历概念代码 前序遍历 概念 概念&#xff1a; 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。 简单点来说就是&#xff1a;根 左子树 右子树的访问顺序 例如&#xff1a;…

Win11 Python3.10 安装pytorch3d

0&#xff0c;背景 Python3.10、cuda 11.7、pytorch 2.0.1 阅读【深度学习】【三维重建】windows10环境配置PyTorch3d详细教程-CSDN博客 1&#xff0c;解决方法 本来想尝试&#xff0c;结果发现CUB安装配置对照表里没有cuda 11.7对应的版本&#xff0c;不敢轻举妄动&#x…

【分布式系统】ELK 企业级日志分析系统

目录 一.ELK概述 1.简介 1.1.可以添加的其他组件 1.2.filebeat 结合 logstash 带来好处 2.为什么使用ELK 3.完整日志系统基本特征 4.工作原理 二.部署ELK日志分析系统 1.初始化环境 2.完成JAVA部署 三. ELK Elasticsearch 集群部署 1.安装 2.修改配置文件 3.es 性…

DDR3(三)

目录 1 预取1.1 什么是预取1.2 预取有哪些好处1.3 结构框图1.4 总结 2 突发2.1 什么是突发2.2 突发与预取 本文讲解DDR中常见的两个术语&#xff1a;预取和突发&#xff0c;对这两个概念理解的关键在于地址线的低位是否参与译码&#xff0c;具体内容请继续往下看。 1 预取 1.1…

利用 Hexo 搭建个人博客

〇、前言 本文将会讨论&#xff0c;如何将 CSDN 上的博客&#xff0c;拉取到本地&#xff0c;然后PicGo、Hexo、Github 等工具建立个人博客&#xff0c;环境为 Ubuntu 20.04。 一、利用 Hexo 预备工作 首先安装 Node.js、npm、git工具。 > node -v v12.22.9 > npm -…