0%

当你不想在新文件夹里再跑一次 BibTeX,只想把已经“编译好”的参考文献带过去(适用于保持回复信中的参考文献顺序和文章中的一致),你至少要拷以下几个文件:

  1. .bbl 这是 BibTeX 运行后生成的含所有条目的正文文件,LaTeX 在第二轮编译时会直接把它当作 .tex 插入。
  2. .bst 这是你用来格式化参考文献的样式文件,如果目标工程里还没有,就要一并拷过去。
  3. .bib 如果目标工程以后还要对条目做增删改,或者要重新跑 BibTeX,就也把原始的 .bib 带上。
  4. .aux 只有当你要完全复刻交叉引用编号或者要保证引用顺序完全一致时才需要,一般不必。

仪器安装

无人机安装+RTK安装

航线规划

按照公司给的文件计算飞速等设置(要求其中一条航线包含灰布)

参数设置

自动曝光+白帧+黑帧

自动曝光:将飞机抬起来对着灰布,要求迎着太阳,摄像头拍的灰布区域不会被影子挡住,点击自动曝光

白帧:将飞机抬起来对着灰布,要求迎着太阳,摄像头拍的灰布区域不会被影子挡住,点击白帧

黑帧:将飞机放在地面上,盖着镜头盖,点击黑帧

飞行

起飞+绕8字+按航线飞行+(过灰布)

如果航线不过灰布的话需要手动飞一条航线过灰布

ar-app使用教程

ar_app文件夹:

image-20230911090458858

数据与输出文件夹:建议按以下路径放置,可以更改

image-20230911090809952

ar_app使用

image-20230911095706333

其中:

—input_path:输入路径

路径下有两个文件夹:

  • mapping:构建库的图片(不可动)
  • query:存储定位图片的临时文件夹(需要定期删除里面的图片)

image-20230911103431355

—output_path:输出路径

里面有若干定位所需要的文件,不可更改

image-20230911103637786

—host:本机IP

本机电脑IP地址,服务发布的位置

—port:服务运行的IP

—number_retrieval:定位前图片检索的张数

数量可以设置为100,可以根据定位效果调整,这个对定位效率影响较小

—init_match_num:初始化图片用于定位需要的图片数目

这个对初始化定位速率影响较大,数量越多,定位精度越高,但定位效率越低

—navigation_match_num:导航过程中用于定位的图片数目

这个对导航定位数量影响较大,如上所述,可以根据精度和定位效率要求进行更改,默认为10

发起请求与返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 wx.uploadFile({
filePath: res.tempFilePath,
name: 'image',
url: 'http://10.104.31.14:5001/upLoadImg_api',
success:(res)=>{
let x_y_data = JSON.parse(res.data)
if(x_y_data.status === "floor"){
wx.showLoading({
title: '行走楼梯中',
mask: True
})
}else{
this.addPointToMap(x_y_data.x, x_y_data.y,"image")
wx.hideLoading()
}

if(this.is_end === false){
this.upLoadImage()
}
},
fail:(res)=>{
console.log(res)
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import json
import os
import time
import requests
url = "http://192.168.20.146:5001/upLoadImg_api"
src_dir = "cz_1"
images = os.listdir(src_dir)
images = sorted(images, key=lambda x: int(x.split(".")[0]))
for image in images:
file = os.path.join(src_dir, image)
files = {'image': open(file, 'rb')}
start_time = time.time()
r = requests.post(url=url, files=files)
end_time = time.time()
print(end_time-start_time, r.content)

返回值:

1
2
3
4
5
6
7
8
9
{

x:x坐标,

y:坐标,

status:"floor"时表示定位失误

}

一、本地使用

1.一般使用

新建项目:

image-20230907161016140

引擎设置:确保项目的jobs路径和引擎监听的jobs路径相同

image-20230907162128310

image-20230907162234601

导入图片:

image-20230907161046985

空三:block名上右键

image-20230907162010342

image-20230907164531702

重建:空三后的block上右键

image-20230907164632789

image-20230907164809754

image-20230907164831639

image-20230907164924132

2.导入其他软件的空三结果

注意导入的xml文件中图片的路径要和导入图片的路径一样,也就是需要更改一下这个路径,在3D view里去看一下是否图片可以找到

image-20230907170005855

二、集群使用

集群三个部分:Master机器+文件存储机器+工作机器(引擎)

1.集群项目的建立

项目路径要为网络路径

image-20230907171142785

引擎设置:

image-20230907171421385

image-20230907171459799

其余和非集群类似

image-20230907171558691

2.特殊处理方法(特殊问题)

2.1.带宽限制

集群所有的机器都会在文件存储机器上面读写,因此有一定的带宽限制,开的集群机器数目不能太多,可以适当超过带宽限制一点点

image-20230907172028754

2.2.项目太大,导致提交项目后有一定的问题

分tiles提交,一次只提交一部分tiles

python中常见错误

opencv相关

最基础的imread、imwrite都不能使用

1
cv2.error: OpenCV(4.2.0) C:\projects\opencv-python\opencv\modules\highgui\src\window.cpp:651: error: (-2:Unspecified error) The function is not implemented.

解决办法:降低python版本为3.7

环境配置

安装 — MMPose 1.1.0 文档

注意:python版本使用3.7的,要不然opencv会出错,什么原因不知道

错误明细

手势识别运行

  • 图片手势识别
1
python demo/topdown_demo_with_mmdet.py demo/mmdetection_cfg/cascade_rcnn_x101_64x4d_fpn_1class.py cascade_rcnn_x101_64x4d_fpn_20e_onehand10k-dac19597_20201030.pth configs/hand_2d_keypoint/topdown_heatmap/onehand10k/td-hm_hrnetv2-w18_8xb64-210e_onehand10k-256x256.py hrnetv2_w18_onehand10k_256x256-30bc9c6b_20210330.pth --input tests/data/onehand10k/9.jpg --show --draw-heatmap

深度学习原理

梯度下降

深度学习简单实现

最基础线性规划实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import tensorflow as tf
from tensorflow.keras import datasets
(x, y), (x_val, y_val) = datasets.mnist.load_data()
# 加载数据
x = tf.convert_to_tensor(x, dtype=tf.float32) / 255.
y = tf.convert_to_tensor(y, dtype=tf.int32)
print(x.shape, y.shape)
# 将x、y转为tensorflow的db
train_dataset = tf.data.Dataset.from_tensor_slices((x, y))
# 设置batch
train_dataset = train_dataset.batch(200)

# [b, 784] => [b, 256] => [b, 128] => [b, 10]
# []
# 这是在计算过程中需要的参数,也是梯度下降时要变化的东西
w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1))
b1 = tf.Variable(tf.zeros([256]))
w2 = tf.Variable(tf.random.truncated_normal([256, 128], stddev=0.1))
b2 = tf.Variable(tf.zeros([128]))
w3 = tf.Variable(tf.random.truncated_normal([128, 10], stddev=0.1))
b3 = tf.Variable(tf.zeros([10]))

lr = 1e-3

for step, (x, y) in enumerate(train_dataset):
# x:[128, 28, 28]
# y:[128]
# [b, 28, 28] => [b, 28*28]
x = tf.reshape(x, [-1, 28*28])

with tf.GradientTape() as tape:
# x:[b, 28*28]
# h1 = x@w1 + b1
# [b, 784]@[784, 256] + [256]=>[b,256] + [256] => [b, 256]
h1 = x@w1 + b1
h1 = tf.nn.relu(h1)
# [b, 256] => [b, 128]
h2 = h1@w2 + b2
h2 = tf.nn.relu(h2)
# [b, 128] => [b, 10]
out = h2@w3 + b3

# compute loss
# out: [b, 10]
# y:[b] => [b, 10]
y = tf.one_hot(y, depth=10)

# mse = mean(sum(y-out)^2)
# [b,10]
loss = tf.square(y-out)
# mean: scalar
loss = tf.reduce_mean(loss)
# 梯度计算
grads = tape.gradient(loss, [w1, b1, w2, b2, w3, b3])
# 梯度更新
# w1 = w1 - lr * grads[0]
w1.assign_sub(lr * grads[0])
b1.assign_sub(lr * grads[1])
w2.assign_sub(lr * grads[2])
b2.assign_sub(lr * grads[3])
w3.assign_sub(lr * grads[4])
b3.assign_sub(lr * grads[5])

if step % 100 == 0:
print(step, 'loss', float(loss))

使用tensorflow的部分接口实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets, optimizers, Sequential, layers


def data_pre_process(x, y):
x = tf.cast(x, dtype=tf.float32) / 255.
y = tf.cast(y, dtype=tf.int32)

return x, y


def dataLoader():
(x, y), (x_val, y_val) = datasets.fashion_mnist.load_data()
db = tf.data.Dataset.from_tensor_slices((x, y))
db = db.map(data_pre_process).batch(128)

db_val = tf.data.Dataset.from_tensor_slices((x_val, y_val))
db_val = db_val.map(data_pre_process).batch(128)

return db, db_val


if __name__ == "__main__":
# 数据加载
db, db_val = dataLoader()

model = Sequential([
layers.Dense(256, activation=tf.nn.relu),
layers.Dense(128, activation=tf.nn.relu),
layers.Dense(64, activation=tf.nn.relu),
layers.Dense(32, activation=tf.nn.relu),
layers.Dense(10, activation=tf.nn.relu),
])
model.build(input_shape=[None, 28*28])
model.summary()

optimizers = optimizers.Adam(lr=1e-3)
# 迭代
for epoch in range(30):
# 每次迭代过程中会根据batchsize分块计算
for step, (x, y) in enumerate(db):
x = tf.reshape(x, [-1, 28*28])
# 梯度计算
with tf.GradientTape() as tape:
logits = model(x)
y_onehot = tf.one_hot(y, depth=10)
loss_mse = tf.reduce_mean(tf.losses.MSE(y_onehot, logits))
loss_ce = tf.reduce_mean(tf.losses.categorical_crossentropy(y_onehot, logits, from_logits=True))

grads = tape.gradient(loss_ce, model.trainable_variables)
# 梯度更新
optimizers.apply_gradients(zip(grads, model.trainable_variables))

if step % 100 == 0:
print(epoch, step, 'loss:', float(loss_ce), float(loss_mse))
# 测试/验证集精度计算
total_correct = 0
total_num = 0
for x, y in db_val:
x = tf.reshape(x, [-1, 28*28])
logits = model(x)
prob = tf.nn.softmax(logits, axis=1)

pred = tf.argmax(prob, axis=1)
pred = tf.cast(pred, dtype=tf.int32)

correct = tf.equal(pred, y)
correct = tf.reduce_sum(tf.cast(correct, dtype=tf.int32))
total_correct += int(correct)
total_num += x.shape[0]

acc = total_correct/total_num
print(epoch, 'test acc:', float(acc))

tensorflow高级api使用

所有的深度学习都包含上面几个步骤

  • 加载数据
  • 迭代
  • 梯度更新
  • 测试/验证精度计算

因此,tensorflow将上面的固定步骤写在同一的接口中方便使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets, optimizers, Sequential, layers


def data_pre_process(x, y):
x = tf.cast(x, dtype=tf.float32) / 255.
y = tf.cast(y, dtype=tf.int32)

return x, y


def dataLoader():
(x, y), (x_val, y_val) = datasets.fashion_mnist.load_data()
x = x.reshape(60000, 28*28)
y = tf.one_hot(y, depth=10)
db = tf.data.Dataset.from_tensor_slices((x, y))
db = db.map(data_pre_process).batch(128)

db_val = tf.data.Dataset.from_tensor_slices((x_val, y_val))
db_val = db_val.map(data_pre_process).batch(128)

return db, db_val


if __name__ == "__main__":
db, db_val = dataLoader()

model = Sequential([
layers.Dense(256, activation=tf.nn.relu),
layers.Dense(128, activation=tf.nn.relu),
layers.Dense(64, activation=tf.nn.relu),
layers.Dense(32, activation=tf.nn.relu),
layers.Dense(10, activation=tf.nn.relu),
])
model.build(input_shape=[None, 28*28])
model.summary()
# compile中会提供若干参数,如梯度优化方式、误差计算方式、精度评定方式,当然还有更多参数,请阅读文档
model.compile(optimizer=optimizers.Adam(lr=0.0001), loss=tf.losses.CategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
# fit即开始训练,需要输入db和要迭代的次数,注意db中的x和y要和model的输入与输出维度一致
model.fit(db, epochs=1000)

常见问题

过拟合和欠拟合

过拟合:训练精度很高,测试精度不够(可能)

欠拟合:训练精度不够,测试精度也不够(可能)——模型复杂度不够

过拟合解决

  • 更多数据
  • 更简单的模型
  • 数据增强

Regularization

image-20230702195941412

前面是误差,后面是参数的范式,参数的一范式越小说明参数越接近于0,那么拟合出来的模型就越平滑,出现过拟合的可能性就越小

image-20230702200316610

两张regularization方式,分别是一范数二范数

Momentum

image-20230702200957049

动量设置,参数更改的不仅仅由当前梯度的影像,还与上一次梯度的方向有关

Learning rate

image-20230702201327476

学习率一般刚开始比较大,后续慢慢变小,前期学习率大变化快,后续会较慢

提前取消

如果出现了训练精度还在提高,测试精度不提高了,说明已经过拟合,可以停止训练

Dropout

image-20230703092847561

每一次训练都有一些连线可能中断

tensorflow和pytorch的dropout参数是相反的

dropout在做test时不能使用——要手动取消

为什么要卷积

为什么要卷积?不使用简单的Dense层?

  • 数据存储需求大

视野?滑动窗口?这个窗口是卷积核?cv里面锐化模糊边缘提取的卷积核

卷积核的个数,也就是con2d中的两个参数:

  • 卷积核的大小问题

[c, 3, 3]一个卷积核可以将一张图片卷积到一个channels为1的新层次,c为图片的通道数

image-20230703095053915

如图,这个[3, 3, 3]依次对三个通道做乘法,然后将结果加起来得到一个一通道的数据,这个一通道的数据代表着原图像在某一层次上的特征

有时候我们需要更多的特征,这时候就需要[N, c, 3, 3]这样N个卷积来提取特征,就会得到N个通道的特征

如下面的(64, 3)其中的64就是上面的N代表着64个通道的特征,3是卷积核的大小,也就是[c, 3, 3]中的3,c会默认与图片的通道数相同,所以不需要额外设置

1
conv1 = Conv2D(64, 3, activation='relu', padding='same')(inputs)

image-20230702203217415

为什么要下采样(池化)

不同的程度可以获取到不同层级的特征

image-20230703095836625

GNSS数据处理

  • 探地雷达使用过程中,有一个基站RTK、一个绑定在探地雷达上的移动站RTK

    • 由于要用基站RTK去纠正移动站RTK,因此移动站RTK的数据采集时间应当在基站RTK采集时间包含中

    • 对RTK的数据.GNS文件的处理:使用HGO数据处理软件

    • HGO软件中:工具→RINEX转换工具

image-20230416141026463

image-20230416141327150

基站数据处理

  • 基站RTK数据-1
    • 注意转换基站数据时,前10s和后10s可以不要,防止启动和结束时数据的不稳定
    • 起始时间加10,截止时间减10

image-20230416141439657

  • 基站RTK数据-2

image-20230416141815403

  • 转换后结果
    • 转换后出现.o和.p文件

image-20230416142003716

移动站数据处理

  • 移动站RTK数据-1
    • 可以看出其时间在基站RTK数据-1的范围内

image-20230416142434473

  • 移动站RTK数据-2
    • 可以看出其时间在基站RTK数据-2的范围外
    • 则需要对

image-20230416142546036

RTK数据使用IE解算

  • 创建项目——点击左上角圈中的按钮,然后下一步

image-20230416144253784

  • 导入移动站GNSS数据——刚刚转换后的.o文件,然后一直下一步

image-20230416144409124

  • 导入基站GNSS数据——刚刚转换后的.o文件,然后一直下一步

image-20230416145751122

  • 站点信息设置
    • 坐标选项设置为平均值、投影设置为WGS84——然后下一步

image-20230416145850175

image-20230416145933429

GNSS解算

  • process→Process GNSS

image-20230416150105641

  • 参数设置为如图所示——点击process

image-20230416150201370

image-20230416150507288

解算结果导出

  • Output→Export Wizard

    • 注意选择导出文件格式,这里可以选择cor,如果没有用new添加,格式如图所示,可以点击预览如图所示——然后一直下一步

    • cor的配置

      • Header/Footer Options参数设置

        image-20230504140927212

        image-20230504141124302

      • Field Separator参数设置

        image-20230504141349524

        image-20230504141433882

      • Export Variables内各项参数设置

        image-20230504142058164

        具体参数如下图所示:

        image-20230504142134534

        image-20230504142209097

        image-20230504142230608

        image-20230504142257682

image-20230416161042576

image-20230416161121686

image-20230416161150435

image-20230416161525886

探地雷达数据绑定RTK

  • 探地雷达数据每个项目的文件如下所示——有若干个数据,每个数据都包含一个time文件

image-20230416170214005

  • 利用探地雷达的time与GNSS输出文件中的time比较,就可以得到每个探地雷达数据的经纬度与海拔信息——所以要求GNSS的time比探测雷达的time长
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
timeFilePath = 'GPR/2023041102line_time'
corFilePath = 'GPR/2023041102line_cor'
for file_name in os.listdir(timeFilePath):
file_ie = '0411_2.txt' #GNSS解算的轨迹坐标
file_gpr = os.path.join(timeFilePath, file_name) #time文件
day = '2023-04-11'
write_cor = corFilePath+"/" + file_name[0:-4] + 'cor'
ie_txt = pd.read_csv(file_ie, header=None)
gpr_txt = pd.read_csv(file_gpr, header=None)
gpr_iet = []
gpr_n = []
for i in range(len(gpr_txt[0])):
gpr_t = gpr_txt[0][i].split('\t')
gpr_n.append(gpr_t[0])
gpr_iet.append(utc_to_iet(gpr_t[2]))
gpr_n = np.array(gpr_n)
gpr_iet = np.array(gpr_iet)
condition = (ie_txt[0] >= gpr_iet[0]) & (ie_txt[0] <= gpr_iet[len(gpr_iet)-1])
ie_select = np.extract(condition, ie_txt[0])
cor = []
for i in range(len(ie_select)):
num = find(gpr_iet, ie_select[i])
if num == -1:
continue
j = np.searchsorted(ie_txt[0], ie_select[i])
t_cor = iet_to_utc(ie_select[i])
lon = ie_txt[1][j]
lat = ie_txt[2][j]
hei = ie_txt[3][j]
q = ie_txt[4][j]
# print(type(gpr_n[num]))
cor.append(gpr_n[num] + '\t' + day + '\t' + str(t_cor) + '\t' + str(lon) + '\t' + 'N' + '\t' + str(lat) + '\t' + 'E' + '\t' + str(hei) + '\t' + 'M' + '\t' + str(q))
cor = np.array(cor)
np.savetxt(write_cor, cor, fmt = '%s', delimiter='\t')

image-20230416170431791

  • 将生成的cor文件复制回数据文件夹,替代原有的cor,但还会有一些cor为空,这一部分数据在后面是无法使用的

image-20230523155612770

探地雷达数据的处理

  • 打开CrossPoint

    • 需要插U盘,要不然很多功能无法使用
  • 打开同一个项目中的各项文件

    • 如这里的6和7是同一个地方的项目
    • 点进去这个文件夹就可以出现能打开的文件,注意与刚刚的cor对比,如果该文件的cor大小为0kb,这个文件就不能导入
    • 打开后如图所示

image-20230523160222273

image-20230523160257746

image-20230523160422696

数据处理

  • 过滤器设置
    • 目前我也不会设置,先简单打开这两个选项,那么左边的波形就会更加变化,我们将依据这个波形去判断是否有异常

image-20230523160649796

  • 0m深度位置设置,这个是为了使得到的高度正常
    • 按道理来说,第一天反射横线应该是地面,也就是此次的深度为0,但是图示并不是这样
    • 左键点住红色三角并向下拖动,就可以改变0深度位置,注意上下两个都要设置,上面的图为更细节的,也是我们在处理数据过程中用得更多的

image-20230523160828461

image-20230523161008203

  • 波形图对比度调整(应该是叫做对比度)
    • 分为左右两个,左边的调上面的图,右边的调下面的图,一般也就使用左边的调节上面的图
    • 可以多调整实验一下,调整到可以清晰判断就行

image-20230523161225710

  • 显示文件数据设置
    • 在判断过程中,我们经常需要观察两条相邻带之间有相似的异常
    • 因此,可以在中间的波形图区域设置显示多条带,对比着看异常
    • 在Tools→Settings→Data view中设置,设置一般为偶数,因为对每一条带都要一个细节的和一个不那么细节的数据需要展示
    • 设置为6时如下图所示
    • 因为我们不常使用下面那一条不那么细节的数据,因此可以将其缩小,便于我们观察需要的数据(鼠标放在蓝色条带上往下拉,拉倒两条数据的交界处),结果如图所示

image-20230523161833582

image-20230523161858046

image-20230523162031623

  • 异常点标注
    • 如图中的明显异常点,可以标注出来
    • 可以看出,三条带出现了类似的异常点,那么我们用同一种Marker标记
    • 按照这种逻辑将所有的异常标出来,再导出和正射影像叠加分析,如图所示

image-20230523162454371

image-20230523162638582

对齐图片(投影后)

添加图片

image-20230416114600655

全景图片一张可以投影为若干张普通图片,在PhotoScan中可以将一张全景图片所投影出的图片设置为一个组,对其加以约束,会使得图片对齐效果更好

图片分组

  • 首先选中一组图片,将其添加到一个图片组中

image-20230416115019165

image-20230416115131493

  • 保存后项目文件夹下会有一下红线圈出的内容

image-20230416115256851

进入对应的chunk文件夹下

image-20230416115349659

  • 解压chunk.zip得到doc.xml文件

doc.xml内容如图所示,其中包含了我们预设的group,我们只需要将其他camera也组织成group格式就可以分组成功

image-20230416120430188

  • 现将剩余的camera组织为group格式,并输出到txt中,将txt中的结果复制到doc.xml中替换原来的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def photoScanNewChunk():
trunk_xml_path = "D:/anbo_my/test.files/0/doc.xml"
new_trunk_xml_path = "D:/anbo_my/test.files/0/group.txt"
tree = ET.parse(trunk_xml_path)
root = tree.getroot()
cameras_s = root.findall("cameras")
for cameras in cameras_s:
camera_s = cameras.findall("camera")
with open(new_trunk_xml_path, "w") as f:
for i in range(int(len(camera_s)/6)):
f.write(' <group id="' + str(i+1) + '" label="Group ' + str(i + 2) + '" type="station">' + '\n')
# 这里的6是每一组的图像数目
for j in range(6):
camera = camera_s[i*6+j]
f.write(' <camera id="' + str(camera.attrib.get("id"))+'" sensor_id="0" label="'+camera.attrib.get("label")+'"/>'+ '\n')
f.write(' </group>'+ '\n')

注意更改id、label和type的值

image-20230416120313547

  • 重新打开项目文件

image-20230416120711094

对齐图片

Workflow→Align Photos

根据需求更改精度之类的东西

image-20230416121056281

如果对齐成功,就会像下面一样只有一个component,而如果对齐失败就会出现多个component这时就需要其他方法去改进优化

image-20230416121220687

对齐图片(全景图片直接处理)

  • 除了按上述将投影后的图片进行对齐及后续处理,还可以直接使用全景图片进行操作

    • 全景图片数量更少(一张全景图片会投影为若干张普通图片),因此处理速率更快

    • 出现多个component的概率更小

    • 但可能也会出现其他问题

  • 由于是全景图片,因此不存在分group的情况,当然也可以将比较靠近的若干图片分为一组

  • 注意导入图片后要有一个步骤告诉软件我们正在使用全景图片
    • Tools→Camera Calibration

image-20230416121932890

  • 其余步骤与之前相似,得到align后的结果