DOM 优化原理

本文解析了 DOM 操作慢的原因。一是 JS 引擎和渲染引擎跨界交流需通过桥接接口,每次操作 DOM 都有开销;二是对 DOM 修改引发样式更迭会触发回流或重绘。还介绍了提速方法,如减少 DOM 操作、利用 DOM Fragment 缓存批量化操作,以提升性能和代码可维护性。

DOM 为什么这么慢

因为收了“过路费”

把 DOM 和 JavaScript 各自想象成一个岛屿,它们之间用收费桥梁连接。——《高性能 JavaScript》

JS 是很快的,在 JS 中修改 DOM 对象也是很快的。在JS的世界里,一切是简单的、迅速的。但 DOM 操作并非 JS 一个人的独舞,而是两个模块之间的协作。

JS 引擎和渲染引擎(浏览器内核)是独立实现的。当我们用 JS 去操作 DOM 时,本质上是 JS 引擎和渲染引擎之间进行了“跨界交流”。这个“跨界交流”的实现并不简单,它依赖了桥接接口作为“桥梁”(如下图)。

过“桥”要收费——这个开销本身就是不可忽略的。我们每操作一次 DOM(不管是为了修改还是仅仅为了访问其值),都要过一次“桥”。过“桥”的次数一多,就会产生比较明显的性能问题。因此“减少 DOM 操作”的建议,并非空穴来风。

对 DOM 的修改引发样式的更迭

过桥很慢,到了桥对岸,我们的更改操作带来的结果也很慢。

很多时候,我们对 DOM 的操作都不会局限于访问,而是为了修改它。当我们对 DOM 的修改会引发它外观(样式)上的改变时,就会触发回流重绘

这个过程本质上还是因为我们对 DOM 的修改触发了渲染树(Render Tree)的变化所导致的:

  • 回流:当我们对 DOM 的修改引发了 DOM 几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性(其他元素的几何属性和位置也会因此受到影响),然后再将计算的结果绘制出来。这个过程就是回流(也叫重排)。

  • 重绘:当我们对 DOM 的修改导致了样式的变化、却并未影响其几何属性(比如修改了颜色或背景色)时,浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式(跳过了上图所示的回流环节)。这个过程叫做重绘。

由此我们可以看出,重绘不一定导致回流,回流一定会导致重绘。硬要比较的话,回流比重绘做的事情更多,带来的开销也更大。但这两个说到底都是吃性能的,所以都不是什么善茬。我们在开发中,要从代码层面出发,尽可能把回流和重绘的次数最小化。

给你的 DOM “提提速”

知道了 DOM 慢的原因,我们就可以对症下药了。

减少 DOM 操作:少交“过路费”、避免过度渲染

我们来看这样一个例子,HTML 内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>DOM操作测试</title>
</head>
<body>
  <div id="container"></div>
</body>
</html>

此时我有一个假需求——我想往 container 元素里写 10000 句一样的话。如果我这么做:

for(var count=0;count<10000;count++){ 
  document.getElementById('container').innerHTML+='<span>我是一个小测试</span>'
} 

这段代码有两个明显的可优化点。

第一点,过路费交太多了。我们每一次循环都调用 DOM 接口重新获取了一次 container 元素,相当于每次循环都交了一次过路费。前后交了 10000 次过路费,但其中 9999 次过路费都可以用缓存变量的方式节省下来:

// 只获取一次container
let container = document.getElementById('container')
for(let count=0;count<10000;count++){ 
  container.innerHTML += '<span>我是一个小测试</span>'
} 

第二点,不必要的 DOM 更改太多了。我们的 10000 次循环里,修改了 10000 次 DOM 树。我们前面说过,对 DOM 的修改会引发渲染树的改变、进而去走一个(可能的)回流或重绘的过程,而这个过程的开销是很“贵”的。这么贵的操作,我们竟然重复执行了 N 多次!其实我们可以通过就事论事的方式节省下来不必要的渲染:

let container = document.getElementById('container')
let content = ''
for(let count=0;count<10000;count++){ 
  // 先对内容进行操作
  content += '<span>我是一个小测试</span>'
} 
// 内容处理好了,最后再触发DOM的更改
container.innerHTML = content

所谓“就事论事”,就像大家所看到的:JS 层面的事情,JS 自己去处理,处理好了,再来找 DOM 打报告。

事实上,考虑JS 的运行速度,比 DOM 快得多这个特性。我们减少 DOM 操作的核心思路,就是让 JS 去给 DOM 分压

这个思路,在 DOM Fragment 中体现得淋漓尽致。

DocumentFragment 接口表示一个没有父级文件的最小文档对象。它被当做一个轻量版的 Document 使用,用于存储已排好版的或尚未打理好格式的XML片段。因为 DocumentFragment 不是真实 DOM 树的一部分,它的变化不会引起 DOM 树的重新渲染的操作(reflow),且不会导致性能等问题。

在我们上面的例子里,字符串变量 content 就扮演着一个 DOM Fragment 的角色。其实无论字符串变量也好,DOM Fragment 也罢,它们本质上都作为脱离了真实 DOM 树的容器出现,用于缓存批量化的 DOM 操作。

前面我们直接用 innerHTML 去拼接目标内容,这样做固然有用,但却不够优雅。相比之下,DOM Fragment 可以帮助我们用更加结构化的方式去达成同样的目的,从而在维持性能的同时,保住我们代码的可拓展和可维护性。我们现在用 DOM Fragment 来改写上面的例子:

let container = document.getElementById('container')
// 创建一个DOM Fragment对象作为容器
let content = document.createDocumentFragment()
for(let count=0;count<10000;count++){
  // span此时可以通过DOM API去创建
  let oSpan = document.createElement("span")
  oSpan.innerHTML = '我是一个小测试'
  // 像操作真实DOM一样操作DOM Fragment对象
  content.appendChild(oSpan)
}
// 内容处理好了,最后再触发真实DOM的更改
container.appendChild(content)

我们运行这段代码,可以得到与前面两种写法相同的运行结果。
可以看出,DOM Fragment 对象允许我们像操作真实 DOM 一样去调用各种各样的 DOM API,我们的代码质量因此得到了保证。并且它的身份也非常纯粹:当我们试图将其 append 进真实 DOM 时,它会在乖乖交出自身缓存的所有后代节点后全身而退,完美地完成一个容器的使命,而不会出现在真实的 DOM 结构中。这种结构化、干净利落的特性,使得 DOM Fragment 作为经典的性能优化手段大受欢迎,这一点在 jQuery、Vue 等优秀前端框架的源码中均有体现。

相比 DOM 命题的

<think>首先,用户的问题是:“我想了解正射影像DOM的生产原理 请问正射影像 DOM 是如何生成的”。我需要基于提供的引用内容来回答。 关键引用: - 引用[1]:描述了EOS正射影像DOM生成过程,包括几何校正、辐射校正、设置参数和使用OpenCV的warpPerspective函数。 - 引用[2]:提到在GodWork EOS模块中生成DOM,基于空三平差优化后的数据。 - 引用[3]:讨论Pix4d中DOM修编的方法,如镶嵌图编辑器和点云过滤。 - 引用[4]:介绍使用PhotoMap检测和修复DOM拉花扭曲。 - 引用[5]:概述DOM制作步骤,包括影像纠正、DEM使用、接边检查等。 DOM(Digital Orthophoto Map)正射影像是通过纠正遥感图像中的几何畸变生成的,使其具有地理坐标和统一比例尺。核心原理是消除地形起伏和传感器姿态的影响。 生成步骤: 1. **数据准备**:获取遥感图像(如航拍或卫星图像)。 2. **空三加密(Aerial Triangulation)**:确定图像的外方位元素(位置和姿态),通常通过空三平差实现(引用[2]提到基于空三平差优化)。 3. **DEM(Digital Elevation Model)使用**:需要DEM来纠正地形起伏(引用[5]提到DEM用于纠正)。 4. **几何纠正**:将原始图像投影到地面上,消除透视变形。这包括: - 辐射校正:处理光照和传感器影响(引用[1]提到辐射校正)。 - 几何校正:使用homography矩阵或类似变换(引用[1]中的warpPerspective)。 5. **DOM生成**:应用纠正模型生成正射影像。输出是地理参考的栅格图像。 6. **后处理**:包括接边检查、镶嵌、调色(引用[5]提到调色和接边)。 7. **修编**:修复拉花或扭曲(引用[3]和[4]讨论)。 在回答中,我需要: - 使用中文。 - 结构清晰,逐步解释。 - 确保LaTeX语法正确:行内数学用$...$,独立公式用$$...$$。 - 末尾添加引用标识。 - 生成相关问题。 回答结构: 1. **引言**:简要定义DOM。 2. **生产原理**:分步骤解释核心过程。 3. **示例代码**:如果相关,从引用[1]中提取Python代码。 4. **修编部分**:简要提及,但重点是生成原理。 5. **结尾**:总结。 6. **相关问题**:生成3-5个相关问题。 生成相关问题: 基于内容,如: 1. DOM生成中DEM的作用? 2. 如何处理DOM中的拉花现象? 3. 常用软件工具(如Pix4d, EOS)比较? 4. 空三加密在DOM生成中的重要性? 5. DOM修编的技术方法? 确保回答真实可靠:基于引用,避免编造。</think>### 正射影像DOM的生产原理 正射影像DOM(Digital Orthophoto Map)是一种经过几何纠正的遥感影像图,它消除了地形起伏和传感器姿态引起的变形,使图像具有统一比例尺和地理坐标。DOM广泛应用于测绘、城市规划、环境监测等领域。其生产原理基于摄影测量学,核心是通过数字高程模型(DEM)和空三加密数据来纠正原始影像的几何畸变。下面我将逐步解释DOM的生成过程,确保内容真实可靠,并参考了站内权威资料。 #### 步骤1: 数据准备与预处理 - **原始影像获取**:使用无人机、卫星或航空相机采集遥感图像(如JPEG或TIFF格式)。这些图像通常包含透视变形(如建筑物倾斜或地形扭曲)。 - **辐射校正**:处理光照不均、大气散射和传感器噪声。例如,调整亮度、对比度,或使用算法(如直方图均衡化)来标准化影像质量。引用[1]提到,这一步是DOM生成的基础预处理操作。 - **空三加密(Aerial Triangulation)**:通过空三平差优化,计算每张影像的外方位元素(即位置$X, Y, Z$和姿态角$\omega, \phi, \kappa$)。这确保了影像间的精确匹配,是DOM生成的先决条件[^2]。数学上,空三求解的是共线方程: $$ \begin{cases} x = -f \frac{a_1(X - X_s) + b_1(Y - Y_s) + c_1(Z - Z_s)}{a_3(X - X_s) + b_3(Y - Y_s) + c_3(Z - Z_s)} \\ y = -f \frac{a_2(X - X_s) + b_2(Y - Y_s) + c_2(Z - Z_s)}{a_3(X - X_s) + b_3(Y - Y_s) + c_3(Z - Z_s)} \end{cases} $$ 其中,$f$是焦距,$(X_s, Y_s, Z_s)$是摄站坐标,$a_i, b_i, c_i$是旋转矩阵元素。 #### 步骤2: DEM的集成与几何纠正 - **DEM的作用**:数字高程模型提供地表高程数据,用于纠正地形引起的影像变形(如山坡上的拉伸)。引用[5]强调,DEM是纠正正射影像的关键输入,需作为过程成果提交。 - **几何纠正**:将原始影像投影到水平面上。这通过透视变换或仿射变换实现: - 使用homography矩阵(单应性矩阵)将像素坐标映射到地理坐标。 - 例如,引用[1]中的Python代码展示了基于OpenCV的warpPerspective函数实现: ```python import cv2 import numpy as np # 读取原始影像和预处理 image = cv2.imread('input_image.jpg') # 假设homography_matrix来自空三和DEM,定义投影关系 homography_matrix = np.array([...]) # 通常从空三数据计算 width, height = 1000, 1000 # 输出DOM的尺寸 resolution = (0.5, 0.5) # 分辨率(米/像素) origin = (0, 0) # 地理坐标原点 # 执行几何纠正生成DOM dom = cv2.warpPerspective(image, homography_matrix, (width, height)) cv2.imwrite('output_dom.jpg', dom) # 保存DOM ``` 此代码通过warpPerspective函数应用几何变换,消除透视变形[^1]。 #### 步骤3: DOM生成与后处理 - **影像镶嵌**:将多张纠正后的影像拼接成无缝的DOM。引用[5]指出,需确保影像间有足够重叠区,并进行接边检查以避免色差或缝隙。 - **色彩均衡**:使用软件(如Photoshop或专业工具)调整色调,使DOM整体色彩一致[^5]。 - **质量检查**:检测并修复常见问题,如房屋拉花(边缘模糊或扭曲)。引用[4]提到,可通过“异常检测”功能标记问题区域,并修改局部DEM高程来同步更新DOM[^4]。 #### 步骤4: 修编与优化 - **修编方法**:DOM常需后处理以提升精度。引用[3]介绍两种常用技术: 1. **镶嵌图编辑器**:在软件(如Pix4d)中手动绘制区域,选择最优原始影像替换扭曲部分。 2. **点云过滤**:基于分类点云数据,移除噪点后重新生成DOM[^3]。 - **输出**:最终DOM保存为GeoTIFF等格式,附带地理坐标信息。 #### 总结 DOM生成的核心原理是结合DEM和空三数据,通过几何纠正消除影像变形。整个过程涉及数据预处理、DEM集成、几何变换和后处理修编,确保输出影像具有高精度地理参考。引用[2]强调,现代工具如GodWork EOS或Pix4d简化了此流程,但需依赖专业软件和算法[^2][^3]。DOM的精度直接影响应用效果,因此DEM质量和空三优化至关重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值