如何 在 Cesium 中选择部分区域 并渲染保存成 图片

在 Cesium 中选择特定区域并渲染保存为图片,可以通过 ‌绘制矩形选区 + 相机视角调整 + 截图保存‌ 实现。以下是完整方案:


步骤 1:添加矩形绘制工具

使用 Cesium.ScreenSpaceEventHandler 监听鼠标事件,绘制选区并获取地理范围。

复制代码
  
  
  
   
   javascript
   
   Copy Code
  
  
  
  
  
  
   
   
   
    
    
    

    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    


    
    
    

   
   
   

   
   
   

    
    let` handler = `new` `Cesium`.`ScreenSpaceEventHandler`(viewer.`scene`.`canvas`);
`let` startPosition = `null`;
`let` rectangle = `null`;
`
   
   
   
  
  
  

// 监听鼠标按下事件

handler.setInputAction((event) => {

startPosition = event.position;

}, Cesium.ScreenSpaceEventType.LEFT_DOWN);

// 监听鼠标移动事件(绘制临时矩形)

handler.setInputAction((event) => {
if (!startPosition) return;
const currentPosition = event.endPosition;

// 清除之前的矩形
if (rectangle) {

viewer.entities.remove(rectangle);

}

// 计算矩形范围(屏幕坐标转地理坐标)
const cartesianStart = viewer.camera.pickEllipsoid(startPosition);
const cartesianEnd = viewer.camera.pickEllipsoid(currentPosition);
const rect = Cesium.Rectangle.fromCartesianArray([cartesianStart, cartesianEnd]);

// 绘制临时矩形

rectangle = viewer.entities.add({
rectangle: {
coordinates: rect,
material: Cesium.Color.RED.withAlpha(0.3),
outline: true,
outlineColor: Cesium.Color.RED

}

});

}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

// 监听鼠标释放事件(确定选区)

handler.setInputAction(async (event) => {
const endPosition = event.position;
const rectCoordinates = rectangle.rectangle.coordinates.getValue();

// 保存选区范围
const selectedRectangle = rectCoordinates;

// 删除临时矩形

viewer.entities.remove(rectangle);

rectangle = null;

// 调整视角并截图(步骤2)
await captureAndSave(selectedRectangle);

}, Cesium.ScreenSpaceEventType.LEFT_UP);


步骤 2:调整相机视角到选区

将相机视角聚焦到选定的矩形区域。

复制代码
 
 
 
  
  javascript
  
  Copy Code
 
 
 
 
 
 
  
  
  
   
   
   

   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   

  
  
  

  
  
  

   
   async` `function` `captureAndSave`(`rectangle`) {
  `// 调整相机视角到矩形区域`
  viewer.`camera`.`flyTo`({
    `destination`: rectangle,
    `complete`: `() =>` {
      `// 等待渲染完成`
      `setTimeout`(`() =>` {
        `// 截图保存(步骤3)`
        `saveAsImage`();
      }, `1000`); `// 延迟确保渲染完成`
    }
  });
}
`
  
  
  
 
 
 

步骤 3:截图保存为图片

使用 canvas.toDataURL 将当前视图保存为 PNG 图片。

复制代码
 
 
 
  
  javascript
  
  Copy Code
 
 
 
 
 
 
  
  
  
   
   
   

   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   

  
  
  

  
  
  

   
   function` `saveAsImage`(``) {
  `// 获取 Canvas 元素`
  `const` canvas = viewer.`scene`.`canvas`;
`
  
  
  
 
 
 

// 转换为 Data URL
const image = canvas.toDataURL('image/png');

// 创建下载链接
const link = document.createElement('a');

link.download = 'cesium-screenshot.png';

link.href = image;

link.click();

}


完整代码整合

复制代码
 
 
 
  
  html
  
  Copy Code
 
 
 
 
 
 
  
  
  
   
   
   

   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   


   
   
   

  
  
  

  
  
  

   
   <!DOCTYPE html>`
`<html>`
`<head>`
  `<link href="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Widgets/widgets.css" rel="stylesheet">`
  `<script src="https://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js"></script>`
`</head>`
`<body>`
  `<div id="cesiumContainer" style="width: 100%; height: 600px;"></div>`
  `<script>
    const viewer = new Cesium.Viewer('cesiumContainer', {
      terrainProvider: Cesium.createWorldTerrain()
    });

   
   
   
    <span class="hljs-keyword">let</span> handler = <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">let</span> startPosition = <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">let</span> rectangle = <span class="hljs-literal">null</span>;

    <span class="hljs-comment">// 启动矩形绘制工具</span>
    <span class="hljs-keyword">function</span> <span class="hljs-title function_">enableRectangleSelection</span>(<span class="hljs-params"></span>) {
      handler = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Cesium</span>.<span class="hljs-title class_">ScreenSpaceEventHandler</span>(viewer.<span class="hljs-property">scene</span>.<span class="hljs-property">canvas</span>);
      
      handler.<span class="hljs-title function_">setInputAction</span>(<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        startPosition = event.<span class="hljs-property">position</span>;
      }, <span class="hljs-title class_">Cesium</span>.<span class="hljs-property">ScreenSpaceEventType</span>.<span class="hljs-property">LEFT_DOWN</span>);

      handler.<span class="hljs-title function_">setInputAction</span>(<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (!startPosition) <span class="hljs-keyword">return</span>;
        <span class="hljs-keyword">const</span> currentPosition = event.<span class="hljs-property">endPosition</span>;
        <span class="hljs-keyword">if</span> (rectangle) viewer.<span class="hljs-property">entities</span>.<span class="hljs-title function_">remove</span>(rectangle);
        
        <span class="hljs-keyword">const</span> cartesianStart = viewer.<span class="hljs-property">camera</span>.<span class="hljs-title function_">pickEllipsoid</span>(startPosition);
        <span class="hljs-keyword">const</span> cartesianEnd = viewer.<span class="hljs-property">camera</span>.<span class="hljs-title function_">pickEllipsoid</span>(currentPosition);
        <span class="hljs-keyword">const</span> rect = <span class="hljs-title class_">Cesium</span>.<span class="hljs-property">Rectangle</span>.<span class="hljs-title function_">fromCartesianArray</span>([cartesianStart, cartesianEnd]);
        
        rectangle = viewer.<span class="hljs-property">entities</span>.<span class="hljs-title function_">add</span>({
          <span class="hljs-attr">rectangle</span>: { <span class="hljs-attr">coordinates</span>: rect, <span class="hljs-attr">material</span>: <span class="hljs-title class_">Cesium</span>.<span class="hljs-property">Color</span>.<span class="hljs-property">RED</span>.<span class="hljs-title function_">withAlpha</span>(<span class="hljs-number">0.3</span>) }
        });
      }, <span class="hljs-title class_">Cesium</span>.<span class="hljs-property">ScreenSpaceEventType</span>.<span class="hljs-property">MOUSE_MOVE</span>);

      handler.<span class="hljs-title function_">setInputAction</span>(<span class="hljs-keyword">async</span> (event) =&gt; {
        <span class="hljs-keyword">const</span> rectCoordinates = rectangle.<span class="hljs-property">rectangle</span>.<span class="hljs-property">coordinates</span>.<span class="hljs-title function_">getValue</span>();
        viewer.<span class="hljs-property">entities</span>.<span class="hljs-title function_">remove</span>(rectangle);
        rectangle = <span class="hljs-literal">null</span>;
        <span class="hljs-keyword">await</span> <span class="hljs-title function_">captureAndSave</span>(rectCoordinates);
      }, <span class="hljs-title class_">Cesium</span>.<span class="hljs-property">ScreenSpaceEventType</span>.<span class="hljs-property">LEFT_UP</span>);
    }

    <span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">captureAndSave</span>(<span class="hljs-params">rectangle</span>) {
      viewer.<span class="hljs-property">camera</span>.<span class="hljs-title function_">flyTo</span>({
        <span class="hljs-attr">destination</span>: rectangle,
        <span class="hljs-attr">complete</span>: <span class="hljs-function">() =&gt;</span> {
          <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
            <span class="hljs-keyword">const</span> canvas = viewer.<span class="hljs-property">scene</span>.<span class="hljs-property">canvas</span>;
            <span class="hljs-keyword">const</span> image = canvas.<span class="hljs-title function_">toDataURL</span>(<span class="hljs-string">'image/png'</span>);
            <span class="hljs-keyword">const</span> link = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">createElement</span>(<span class="hljs-string">'a'</span>);
            link.<span class="hljs-property">download</span> = <span class="hljs-string">'selected-area.png'</span>;
            link.<span class="hljs-property">href</span> = image;
            link.<span class="hljs-title function_">click</span>();
          }, <span class="hljs-number">1000</span>);
        }
      });
    }

    <span class="hljs-comment">// 初始化工具</span>
    <span class="hljs-title function_">enableRectangleSelection</span>();




  
  
  
 
 
 

</script>
</body>
</html>


关键优化

  1. 高清截图‌:

    复制代码
       
       
       
        
        javascript
        
        Copy Code
       
       
       
       
       
       
        
        
        
         
         
         
    
         
         
         
    
        
        
        
    
        
        
        
    
         
         // 提高分辨率(2倍)`
    viewer.`resolutionScale` = `2`;
    `
        
        
        
       
       
       
  2. 去除水印‌:

    复制代码
       
       
       
        
        javascript
        
        Copy Code
       
       
       
       
       
       
        
        
        
         
         
         
        
        
        
    
        
        
        
    
         
         `viewer.`cesiumWidget`.`creditContainer`.`style`.`display` = `'none'`;
    `
        
        
        
       
       
       
  3. 支持文件命名‌:

    复制代码
       
       
       
        
        javascript
        
        Copy Code
       
       
       
       
       
       
        
        
        
         
         
         
        
        
        
    
        
        
        
    
         
         `link.`download` = ``area-${new Date().toISOString()}.png``;
    `
        
        
        
       
       
       

注意事项

  • 确保 Cesium.Camera.flyTo 的动画完成后截图,避免画面未渲染完成。
  • 如果选区跨越大范围,可能需要调整相机的 pitchroll 以垂直俯视。
  • 跨域图片资源可能导致 toDataURL 失效,需配置服务器 CORS。

通过此方案,您可以在 Cesium 中实现交互式选区并保存为图片。

相关推荐
格林威5 小时前
工业检测机器视觉为啥非用工业相机?普通相机差在哪?
人工智能·数码相机·yolo·计算机视觉·视觉检测·相机
格林威13 小时前
机器视觉检测的光源基础知识及光源选型
人工智能·深度学习·数码相机·yolo·计算机视觉·视觉检测
Hi2024021718 小时前
使用 Apollo TransformWrapper 生成相机到各坐标系的变换矩阵
数码相机·线性代数·矩阵·自动驾驶·apollo
nenchoumi31191 天前
全网首发!Realsense 全新 D555 相机开箱记录与 D435i、L515、D456 横向测评!
数码相机·计算机视觉·机器人·ros·realsense
简单说鸭1 天前
ScanNet: Richly-annotated 3D Reconstructions of Indoor Scenes 数据集构建
数码相机
文弱_书生2 天前
关于对鱼眼相机图片进行畸变校正的两种思路
数码相机·鱼眼畸变校正·传统几何方法·深度学习方法
疾风铸境2 天前
qt+halcon开发相机拍照软件步骤
数码相机·qt·halcon·拍照
北岛三生2 天前
ISP(图像信号处理器)
图像处理·数码相机·测试工具·计算机视觉·测试用例·模块测试
兔子不吃草~3 天前
鱼眼相机模型
数码相机
北岛三生3 天前
Camera tuning flow相机调试流程
图像处理·数码相机·测试工具·模块测试