Threejs中頂視圖截圖

Threejs中頂視圖截圖

一般項目中的每個模型,都需要有一張對應的圖片,一般是頂視圖,在對應的2D場景場景中展示。以下分享一個實現方式,先將清空模型材質的紋理,把顏色設置為白色,使用正交相機截取頂視圖,生成一張圖片,作為模型在2D場景的圖標。

這個是截圖模型頂視圖的代碼:

import * as THREE from 'three';
import { OutlinePostProcess } from './OutlinePostProcess';export class ModelCapture {private renderer: THREE.WebGLRenderer;private scene: THREE.Scene;private camera: THREE.OrthographicCamera;private outlineProcess: OutlinePostProcess;private width: number = 240;private height: number = 260;constructor() {this.scene = new THREE.Scene();this.renderer = new THREE.WebGLRenderer({antialias: true,alpha: true,preserveDrawingBuffer: true});this.camera = new THREE.OrthographicCamera(0, 0, 0, 0, 0.1, 2000)this.camera.position.set(0, 100, 0);this.camera.lookAt(0, 0, 0);const ambientLight = new THREE.AmbientLight(0xffffff, 1);this.scene.add(ambientLight);this.outlineProcess = new OutlinePostProcess(this.renderer,this.scene,this.camera,this.width,this.height);this.outlineProcess.setDefaultEnabled(true);this.outlineProcess.setEnabled(true);this.outlineProcess.makeOutlineDirty();}public captureModel(model: THREE.Group): void {const root = model;this.scene.add(root);const boundingBox = new THREE.Box3().setFromObject(root);const size = new THREE.Vector3();boundingBox.getSize(size);this.updateSize(size.x, size.z);root.traverse((child: THREE.Object3D) => {if (child instanceof THREE.Mesh) {if (Array.isArray(child.material)) {child.material.forEach(material => {if (material.map) material.map = null;material.color = new THREE.Color(1, 1, 1);});} else if (child.material && child.material.map) {child.material.map = null;child.material.color = new THREE.Color(1, 1, 1);}}});this.outlineProcess.makeOutlineDirty();this.outlineProcess.render();const imageUrl = this.renderer.domElement.toDataURL('image/png');const img = document.createElement('img');img.id = 'model-capture';img.src = imageUrl;img.style.position = 'absolute';img.style.top = '0';img.style.right = '0';img.style.width = '20%';img.style.height = '20%';document.body.appendChild(img);}// 更新場景尺寸的函數public updateSize(width: number, height: number) {// 更新渲染器尺寸this.renderer.setSize(width, height)// 更新相機參數this.camera.left = width / -2this.camera.right = width / 2this.camera.top = height / 2this.camera.bottom = height / -2this.camera.updateProjectionMatrix()this.outlineProcess.onResize(width, height);}
} 

為了方便頂視圖的效果,搭建了一個同樣的場景,來實時觀察相機截圖的內容,代碼如下:

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { OutlinePostProcess } from './OutlinePostProcess';
import { ModelCapture } from './ModelCapture';export class TopView {private static initialized = false;private static renderer: THREE.WebGLRenderer;private static scene: THREE.Scene;private static camera: THREE.OrthographicCamera;private static outlineProcess: OutlinePostProcess;private static model: THREE.Group;private static modelCapture: ModelCapture;public static main() {TopView.modelCapture = new ModelCapture();if (TopView.initialized) {return;}TopView.initialized = true;console.log("TopView")this.scene = new THREE.Scene()const container = document.getElementById('main') as HTMLDivElementif (!container) {console.error('找不到容器元素')return}this.renderer = new THREE.WebGLRenderer({antialias: true,alpha: true,preserveDrawingBuffer: true})container.appendChild(this.renderer.domElement)this.camera = new THREE.OrthographicCamera(0, 0, 0, 0, 0.1, 2000)this.outlineProcess = new OutlinePostProcess(this.renderer, this.scene, this.camera, 240, 260);this.updateSize(240, 260)window.addEventListener('resize', ()=>{this.updateSize(240, 260);})this.camera.position.set(0, 100, 0);this.camera.lookAt(0, 0, 0);(globalThis as any).testCamera = TopView.camera;// 添加環境光const ambientLight = new THREE.AmbientLight(0xffffff, 1)this.scene.add(ambientLight)// 添加坐標軸輔助器const axesHelper = new THREE.AxesHelper(500)this.scene.add(axesHelper)// 添加網格輔助器const gridHelper = new THREE.GridHelper(1000, 20)this.scene.add(gridHelper)// 加載 GLB 模型const loader = new GLTFLoader()loader.load('/bed.glb', (gltf: any) => {let root = gltf.scene;root.scale.set(0.1, 0.1, 0.1);root.rotation.set(0, 0, 0);// 獲取模型的包圍盒const boundingBox = new THREE.Box3().setFromObject(root);const size = new THREE.Vector3();boundingBox.getSize(size);console.log('模型尺寸:', size);TopView.scene.add(root);TopView.model = root.clone();}, undefined, (error: any) => {console.error('加載模型出錯:', error)})// 添加場景控制器const controls = new OrbitControls(this.camera, this.renderer.domElement)controls.enableDamping = true // 啟用阻尼效果controls.dampingFactor = 0.05 // 阻尼系數controls.screenSpacePanning = false // 禁用屏幕空間平移controls.minDistance = 100 // 最小縮放距離controls.maxDistance = 500 // 最大縮放距離controls.maxPolarAngle = Math.PI / 2 // 限制垂直旋轉角度// 渲染場景function animate() {requestAnimationFrame(animate)controls.update() // 更新控制器// TopView.renderer.render(TopView.scene, TopView.camera)TopView.outlineProcess.makeOutlineDirty();TopView.outlineProcess.render();}animate()}// 更新場景尺寸的函數public static updateSize(width: number, height: number) {// 更新渲染器尺寸this.renderer.setSize(width, height)// 更新相機參數this.camera.left = width / -2this.camera.right = width / 2this.camera.top = height / 2this.camera.bottom = height / -2this.camera.updateProjectionMatrix()this.outlineProcess.onResize(width, height);}public static async captureScene() {this.outlineProcess.makeOutlineDirty();this.outlineProcess.render();let imageUrl = await this.renderer.domElement.toDataURL('image/png');const img = await document.createElement('img');img.id = 'scene-capture';img.src = imageUrl;img.style.position = 'absolute';img.style.top = '0';img.style.left = '0';img.style.width = '20%';img.style.height = '20%';document.body.appendChild(img);}// 創建一個函數來捕獲渲染結果public static async captureModel() {await TopView.modelCapture.captureModel(TopView.model.clone())}
}(globalThis as any).TopView = TopView;

可以在控制臺輸入如下代碼,調用 TopView 中的兩個方法,來測試:

// 截取當前場景
TopView.captureScene()
// 使用截圖工具類截圖
TopView.captureModel()

效果如下,左邊是截取的場景,右邊是截圖工具類截的圖。
res
其中,用到的描邊方式,我在上一篇博客中有介紹,代碼有一點修改,便于調式,也把源碼放在下面。

import * as THREE from "three";
import { EffectComposer, FXAAShader, GammaCorrectionShader, RenderPass, ShaderPass, SMAAPass } from "three/examples/jsm/Addons.js";export class OutlinePostProcess {private _composer!: EffectComposer;private _normalIdRenderTarget!: THREE.WebGLRenderTarget;private _renderPass!: RenderPass;private _outlinePass!: ShaderPass;private _fxaaPass!: ShaderPass;private _smaaPass!: SMAAPass;// 抗鋸齒模式,0: FXAA,1: SMAAprivate _aaMode: number = 0;private _defaultEnabled: boolean = true;private _enabled: boolean = true;private _isRenderingNormalId: boolean = false;private _normalIdMaterial!: THREE.ShaderMaterial;// 避免每幀都重復渲染一次描邊,場景沒變化時無需渲染private _outlineDirty: boolean = true;// 是否啟用對角線采樣private _enableDiagonalSampling: boolean = false;constructor(private renderer: THREE.WebGLRenderer,private scene: THREE.Scene,private _camera: THREE.Camera,private _width: number,private _height: number,) {this.initNormalIdMaterial();this.initRenderTarget();this.initComposer();}public set camera(camera: THREE.Camera) {this._camera = camera;this._renderPass.camera = camera;this.makeOutlineDirty();}public get width() {const pixelRatio = this.renderer.getPixelRatio();return this._width * pixelRatio;}public get height() {const pixelRatio = this.renderer.getPixelRatio();return this._height * pixelRatio;}private initNormalIdMaterial() {this._normalIdMaterial = new THREE.ShaderMaterial({uniforms: {meshID: { value: 0.0 }},vertexShader: `varying vec3 vNormal;void main() {vNormal = normalize(normalMatrix * normal);gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`,fragmentShader: `uniform float meshID;varying vec3 vNormal;vec2 encodeNormal(vec3 n) {vec2 enc = normalize(n.xy) * (sqrt(-n.z * 0.5 + 0.5));enc = enc * 0.5 + 0.5;return enc;}vec2 encodeID(float id) {float tempID = id / 255.0;float highID = floor(tempID);return vec2(highID / 255.0, tempID - highID);}void main() {vec2 encodedNormal = encodeNormal(normalize(vNormal));vec2 encodedID = encodeID(meshID);gl_FragColor = vec4(encodedNormal, encodedID);}`});}private switchMaterial(isNormalId: boolean) {if (isNormalId === this._isRenderingNormalId) {return;}let meshID = 1;const processMesh = (object: THREE.Object3D, parentSkipOutline: boolean = false) => {// 如果父級節點禁用描邊,則當前節點也禁用描邊const skipOutline = parentSkipOutline || object.userData.SkipOutline;// 檢查對象是否可見if (!object.visible) {return;}if (object instanceof THREE.Mesh ||object instanceof THREE.Line ||object instanceof THREE.Points ||object instanceof THREE.Sprite) {if (isNormalId) {object.userData.originalMaterial = object.material;let normalIdMaterial = object.userData.normalIdMaterial;if (!normalIdMaterial) {normalIdMaterial = this._normalIdMaterial.clone();object.userData.normalIdMaterial = normalIdMaterial;}normalIdMaterial.uniforms.meshID.value = skipOutline ? 0 : meshID++;object.material = normalIdMaterial;} else {object.material = object.userData.originalMaterial;}}// 遞歸處理所有子節點object.children.forEach(child => processMesh(child, skipOutline));};// 從場景根節點開始處理processMesh(this.scene);this._isRenderingNormalId = isNormalId;}private initRenderTarget() {this._normalIdRenderTarget = new THREE.WebGLRenderTarget(this.width,this.height,{format: THREE.RGBAFormat,type: THREE.FloatType,minFilter: THREE.NearestFilter,magFilter: THREE.NearestFilter,colorSpace: THREE.SRGBColorSpace,count: 1});}private initComposer() {this._composer = new EffectComposer(this.renderer);// 添加主渲染通道this._renderPass = new RenderPass(this.scene, this._camera);this._composer.addPass(this._renderPass);// 放在renderPass之后,修復渲染后顏色變暗的問題const gammaCorrectionShader = new ShaderPass(GammaCorrectionShader);this._composer.addPass(gammaCorrectionShader);// 添加輪廓后處理通道this._outlinePass = new ShaderPass({uniforms: {tDiffuse: { value: null },tNormalId: { value: null },resolution: { value: new THREE.Vector2(1 / this.width, 1 / this.height) },outlineColor: { value: new THREE.Vector4(0.0, 0.0, 0.0, 1.0) },lowIDConfig: { value: 1.0 },lowNormalConfig: { value: 0.8 },intensityConfig: { value: 0.3 },enableDiagonalSampling: { value: this._enableDiagonalSampling }},vertexShader: `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`,fragmentShader: `uniform sampler2D tDiffuse;uniform sampler2D tNormalId;uniform vec2 resolution;uniform vec4 outlineColor;uniform float lowIDConfig;uniform float lowNormalConfig;uniform float intensityConfig;uniform bool enableDiagonalSampling;varying vec2 vUv;vec3 decodeNormal(vec2 enc) {vec4 nn = vec4(enc, 0.0, 0.0) * vec4(2.0,2.0,0.0,0.0) + vec4(-1.0,-1.0,1.0,-1.0);float l = dot(nn.xyz,-nn.xyw);nn.z = l;nn.xy *= sqrt(l);return nn.xyz * 2.0 + vec3(0.0,0.0,-1.0);}float decodeID(vec2 enc) {return floor((enc.x * 255.0 + enc.y) * 255.0 + 0.5);}// 采樣輔助函數vec2 sampleDirection(vec2 uv, vec2 offset, vec3 currentNormal, float currentID) {vec4 texSample = texture2D(tNormalId, uv + offset);float id = decodeID(texSample.zw);if(id < 0.5) {return vec2(0.0);}vec3 normalSample = decodeNormal(texSample.xy);float normalDiff = 1.0 - abs(dot(currentNormal, normalSample));float idDiff = abs(currentID - id) < 0.0001 ? 0.0 : 1.0;return vec2(normalDiff, idDiff);}void main() {vec4 tex = texture2D(tNormalId, vUv);if(tex.x == 0.0 && tex.y == 0.0 && tex.z == 0.0) {gl_FragColor = texture2D(tDiffuse, vUv);return;}float currentID = decodeID(tex.zw);if(currentID < 0.5) {gl_FragColor = texture2D(tDiffuse, vUv);return;}vec3 currentNormal = decodeNormal(tex.xy);// 使用采樣輔助函數處理四個方向vec2 rightSample = sampleDirection(vUv, vec2(resolution.x, 0.0), currentNormal, currentID);vec2 leftSample = sampleDirection(vUv, vec2(-resolution.x, 0.0), currentNormal, currentID);vec2 downSample = sampleDirection(vUv, vec2(0.0, resolution.y), currentNormal, currentID);vec2 upSample = sampleDirection(vUv, vec2(0.0, -resolution.y), currentNormal, currentID);// 處理對角線方向的采樣float diagonalIdDiff = 0.0;float diagonalNormalDiff = 0.0;if(enableDiagonalSampling) {vec2 rightUpSample = sampleDirection(vUv, vec2(resolution.x, -resolution.y), currentNormal, currentID);vec2 rightDownSample = sampleDirection(vUv, vec2(resolution.x, resolution.y), currentNormal, currentID);vec2 leftUpSample = sampleDirection(vUv, vec2(-resolution.x, -resolution.y), currentNormal, currentID);vec2 leftDownSample = sampleDirection(vUv, vec2(-resolution.x, resolution.y), currentNormal, currentID);diagonalNormalDiff = rightUpSample.x + rightDownSample.x + leftUpSample.x + leftDownSample.x;diagonalIdDiff = rightUpSample.y + rightDownSample.y + leftUpSample.y + leftDownSample.y;}float totalIdDiff = rightSample.y + leftSample.y + downSample.y + upSample.y + diagonalIdDiff * 0.5;float totalNormalDiff = rightSample.x + leftSample.x + downSample.x + upSample.x + diagonalNormalDiff * 0.5;vec2 result = clamp(vec2(totalNormalDiff * lowNormalConfig, totalIdDiff * lowIDConfig) * intensityConfig,0.0,1.0);float outlineStrength = max(result.x, result.y);vec4 sceneColor = texture2D(tDiffuse, vUv);gl_FragColor = mix(sceneColor, outlineColor, outlineStrength * outlineColor.a);}`});this._composer.addPass(this._outlinePass);if (this._aaMode === 0) {// 添加FXAA抗鋸齒通道this._fxaaPass = new ShaderPass(FXAAShader);this._fxaaPass.material.uniforms.resolution.value.x = 1 / (this.width);this._fxaaPass.material.uniforms.resolution.value.y = 1 / (this.height);this._composer.addPass(this._fxaaPass);}else {// 創建 SMAA Passthis._smaaPass = new SMAAPass(this.width, this.height);this._composer.addPass(this._smaaPass);}}public setEnabled(enabled: boolean) {this._enabled = enabled;if (enabled) {this._outlineDirty = true;}}public setDefaultEnabled(t: boolean) {this._defaultEnabled = t;}public get isEnabled(): boolean {return this._enabled;}public get isDefaultEnabled() {return this._defaultEnabled;}public onResize(w: number, h: number) {this._width = w;this._height = h;// 更新渲染器尺寸this.renderer.setSize(this.width, this.height, false);// 更新后處理效果尺寸this._normalIdRenderTarget.setSize(this.width, this.height);this._composer.setSize(this.width, this.height);this._outlinePass.uniforms.resolution.value.set(1 / this.width, 1 / this.height);// 更新抗鋸齒通道尺寸if (this._aaMode === 0) {this._fxaaPass.material.uniforms.resolution.value.x = 1 / (this.width);this._fxaaPass.material.uniforms.resolution.value.y = 1 / (this.height);}else {this._smaaPass.setSize(this.width, this.height);}}public render() {if (!this._enabled) {// 如果禁用了描邊效果,直接進行普通渲染this.renderer.render(this.scene, this._camera);return;}// 渲染法線和ID到渲染目標if (this._outlineDirty) {this.switchMaterial(true);this.renderer.setRenderTarget(this._normalIdRenderTarget);this.renderer.render(this.scene, this._camera);this._outlineDirty = true;}// 更新輪廓通道的紋理this._outlinePass.uniforms.tNormalId.value = this._normalIdRenderTarget.texture;// this.showRenderTarget(this.renderer, this._normalIdRenderTarget, this.width, this.height);// 恢復正常渲染this.switchMaterial(false);this.renderer.setRenderTarget(null);// 執行后處理渲染this._composer.render();}public makeOutlineDirty() {this._outlineDirty = true;}public setLowIDConfig(value: number) {this._outlinePass.uniforms.lowIDConfig.value = value;this.makeOutlineDirty();}public getLowIDConfig() {return this._outlinePass.uniforms.lowIDConfig.value;}public setLowNormalConfig(value: number) {this._outlinePass.uniforms.lowNormalConfig.value = value;this.makeOutlineDirty();}public getLowNormalConfig() {return this._outlinePass.uniforms.lowNormalConfig.value;}public setIntensityConfig(value: number) {this._outlinePass.uniforms.intensityConfig.value = value;this.makeOutlineDirty();}public getIntensityConfig() {return this._outlinePass.uniforms.intensityConfig.value;}// 設置是否啟用對角線采樣public setEnableDiagonalSampling(enable: boolean) {this._enableDiagonalSampling = enable;this._outlinePass.uniforms.enableDiagonalSampling.value = enable;this.makeOutlineDirty();}// 獲取是否啟用對角線采樣public getEnableDiagonalSampling(): boolean {return this._enableDiagonalSampling;}public getOutlineColor(): THREE.Vector4 {return this._outlinePass.uniforms.outlineColor.value;}public setOutlineColor(x: number, y: number, z: number) {this._outlinePass.uniforms.outlineColor.value.set(x, y, z, 1);}public showRenderTarget(render: THREE.WebGLRenderer, target: THREE.WebGLRenderTarget, width: number, height: number) {// 根據渲染目標的格式選擇正確的數據類型let pixels;if (target.texture.type === THREE.FloatType) {pixels = new Float32Array(width * height * 4);} else {pixels = new Uint8Array(width * height * 4);}// 將 renderTarget 的紋理數據讀取到 Canvas 上render.setRenderTarget(target);render.readRenderTargetPixels(target, 0, 0, width, height, pixels);render.setRenderTarget(null);// 將 Canvas 數據展示到 img let imgElement = document.getElementById('normalIdTexture') as HTMLImageElement;if (!imgElement) {imgElement = document.createElement('img');imgElement.id = 'normalIdTexture';// 添加樣式使圖片可見imgElement.style.position = 'fixed';imgElement.style.top = '120px';imgElement.style.left = '10px';imgElement.style.width = '400px';imgElement.style.height = 'auto';imgElement.style.border = '1px solid #ccc';imgElement.style.zIndex = '100000';document.body.appendChild(imgElement);}const canvas = document.createElement('canvas');canvas.width = width;canvas.height = height;const ctx = canvas.getContext('2d');if (ctx) {let uint8ClampedArray;if (pixels instanceof Float32Array) {// 如果是 Float32Array,需要將數據轉換為 Uint8ClampedArrayuint8ClampedArray = new Uint8ClampedArray(width * height * 4);for (let i = 0; i < pixels.length; i++) {uint8ClampedArray[i] = Math.min(255, Math.max(0, pixels[i] * 255));}} else {uint8ClampedArray = new Uint8ClampedArray(pixels);}// 確保 alpha 通道不透明// for (let i = 3; i < pixels.length; i += 4) {//     uint8ClampedArray[i] = 255;// }const imageData = new ImageData(uint8ClampedArray, width, height);// 創建臨時 Canvas 來存儲原始圖像const tempCanvas = document.createElement('canvas');tempCanvas.width = width;tempCanvas.height = height;const tempCtx = tempCanvas.getContext('2d');if (tempCtx) {tempCtx.putImageData(imageData, 0, 0);// 使用 GPU 加速的變換來翻轉圖像ctx.save();ctx.scale(1, -1);ctx.translate(0, -height);ctx.drawImage(tempCanvas, 0, 0);ctx.restore();}}imgElement.src = canvas.toDataURL();}
} 

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/78475.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78475.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/78475.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深度探索:DeepSeek賦能WPS圖表繪制

一、研究背景 在當今數字化信息爆炸的時代&#xff0c;數據處理與可視化分析已成為眾多領域研究和決策的關鍵環節。隨著數據量的急劇增長和數據維度的不斷豐富&#xff0c;傳統的數據可視化工具在應對復雜數據時逐漸顯露出局限性。Excel作為廣泛應用的電子表格軟件&#xff0c;…

第11章 面向分類任務的表示模型微調

??????第1章 對大型語言模型的介紹第2章 分詞和嵌入第3章 解析大型語言模型的內部機制第4章 文本分類第5章 文本聚類與主題建模第6章 提示工程第7章 高級文本生成技術與工具第8章 語義搜索與檢索增強生成第9章 多模態大語言模型第10章 構建文本嵌入模型第12章 微調生成模…

4.換行和續寫

一.FileOutputStream寫出數據的兩個小問題&#xff1a; 問題一&#xff1a;換行 假設在本地文件中要輸出數據aweihaoshuai 666&#xff0c;在輸出這個數據時要換行寫出&#xff0c;如下圖&#xff1a; 問題二&#xff1a;續寫 假設在一個文本文件中已經存在數據aweihaoshuai…

聯易融受邀參加上海審計局金融審計處專題交流座談

近日&#xff0c;聯易融科技集團受邀出席了由上海市審計局金融審計處組織的專題交流座談&#xff0c;憑借其在供應鏈金融領域的深厚積累和創新實踐&#xff0c;聯易融為與會人員帶來了精彩的分享&#xff0c;進一步加深現場對供應鏈金融等金融發展前沿領域的理解。 在交流座談…

SOC估算:開路電壓修正的安時積分法

SOC估算&#xff1a;開路電壓修正的安時積分法 基本概念 開路電壓修正的安時積分法是一種結合了兩種SOC估算方法的混合技術&#xff1a; 安時積分法&#xff08;庫侖計數法&#xff09; - 通過電流積分計算SOC變化 開路電壓法 - 通過電池電壓與SOC的關系曲線進行校準 方法原…

代碼隨想錄打卡|Day27(合并區間、單調遞增的數字、監控二叉樹)

貪心算法 Part05 合并區間 力扣題目鏈接 代碼隨想錄鏈接 視頻講解鏈接 題目描述&#xff1a; 以數組 intervals 表示若干個區間的集合&#xff0c;其中單個區間為 intervals[i] [starti, endi] 。請你合并所有重疊的區間&#xff0c;并返回 一個不重疊的區間數組&#xff0…

PostgreSQL的擴展 pg_cron

PostgreSQL的擴展 pg_cron pg_cron 是 PostgreSQL 的一個開源擴展&#xff0c;它允許在數據庫內部使用 cron 語法調度定期任務&#xff0c;是最接近 Oracle DBMS_SCHEDULER 的解決方案。 一 安裝與配置 1 安裝方法 下載路徑&#xff1a; https://github.com/citusdata/pg_…

卷積神經網絡遷移學習:原理與實踐指南

引言 在深度學習領域&#xff0c;卷積神經網絡(CNN)已經在計算機視覺任務中取得了巨大成功。然而&#xff0c;從頭開始訓練一個高性能的CNN模型需要大量標注數據和計算資源。遷移學習(Transfer Learning)技術為我們提供了一種高效解決方案&#xff0c;它能夠將預訓練模型的知識…

圖論---樸素Prim(稠密圖)

O( n ^2 ) 題目通常會提示數據范圍&#xff1a; 若 V ≤ 500&#xff0c;兩種方法均可&#xff08;樸素Prim更穩&#xff09;。 若 V ≤ 1e5&#xff0c;必須用優先隊列Prim vector 存圖。 // 最小生成樹 —樸素Prim #include<cstring> #include<iostream> #i…

Spring-Cache替換Keys為Scan—負優化?

背景 使用ORM工具是往往會配合緩存框架實現三級緩存提高查詢效率&#xff0c;spring-cache配合redis是非常常規的實現方案&#xff0c;如未做特殊配置&#xff0c;CacheEvict(allEntries true) 的批量驅逐方式&#xff0c;默認使用keys的方式查詢歷史緩存列表而后delete&…

【N8N】Docker Desktop + WSL 安裝過程(Docker Desktop - WSL update Failed解決方法)

背景說明&#xff1a; 因為要用n8n&#xff0c;官網推薦這個就下載了&#xff0c;然后又是一堆卡的安裝問題記錄過程。 1. 下載安裝包 直接去官網Get Docker | Docker Docs下載 下載的是第一個windows - x86_64. &#xff08;*下面那個beta的感覺是測試版&#xff09; PS&am…

RT Thread 發生異常時打印輸出cpu寄存器信息和棧數據

打印輸出發生hardfault時,當前棧十六進制數據和cpu寄存器信息 在發生 HardFault 時,打印當前棧的十六進制數據和 CPU 寄存器信息是非常重要的調試手段。以下是如何實現這一功能的具體步驟和示例代碼。 1. 實現 HardFault 處理函數 我們需要在 HardFault 中捕獲異常上下文,…

【安裝neo4j-5.26.5社區版 完整過程】

1. 安裝java 下載 JDK21-windows官網地址 配置環境變量 在底下的系統變量中新建系統變量&#xff0c;變量名為JAVA_HOME21&#xff0c;變量值為JDK文件夾路徑&#xff0c;默認為&#xff1a; C:\Program Files\Java\jdk-21然后在用戶變量的Path中&#xff0c;添加下面兩個&am…

android jatpack Compose 多數據源依賴處理:從狀態管理到精準更新的架構設計

Android Compose 多接口數據依賴管理&#xff1a;ViewModel 狀態共享最佳實踐 &#x1f4cc; 問題背景 在 Jetpack Compose 開發中&#xff0c;經常遇到以下場景&#xff1a; 頁面由多個獨立接口數據組成&#xff08;如 Part1、Part2&#xff09;Part2 的某些 UI 需要依賴 P…

面試之消息隊列

消息隊列場景 什么是消息隊列&#xff1f; 消息隊列是一個使用隊列來通信的組件&#xff0c;它的本質就是個轉發器&#xff0c;包含發消息、存消息、消費消息。 消息隊列怎么選型&#xff1f; 特性ActiveMQRabbitMQRocketMQKafka單機吞吐量萬級萬級10萬級10萬級時效性毫秒級…

GStreamer 簡明教程(十一):插件開發,以一個音頻生成(Audio Source)插件為例

系列文章目錄 GStreamer 簡明教程&#xff08;一&#xff09;&#xff1a;環境搭建&#xff0c;運行 Basic Tutorial 1 Hello world! GStreamer 簡明教程&#xff08;二&#xff09;&#xff1a;基本概念介紹&#xff0c;Element 和 Pipeline GStreamer 簡明教程&#xff08;三…

Linux kernel signal原理(下)- aarch64架構sigreturn流程

一、前言 在上篇中寫到了linux中signal的處理流程&#xff0c;在do_signal信號處理的流程最后&#xff0c;會通過sigreturn再次回到線程現場&#xff0c;上篇文章中介紹了在X86_64架構下的實現&#xff0c;本篇中介紹下在aarch64架構下的實現原理。 二、sigaction系統調用 #i…

華為OD機試真題——簡易內存池(2025A卷:200分)Java/python/JavaScript/C++/C/GO最佳實現

2025 A卷 200分 題型 本文涵蓋詳細的問題分析、解題思路、代碼實現、代碼詳解、測試用例以及綜合分析&#xff1b; 并提供Java、python、JavaScript、C、C語言、GO六種語言的最佳實現方式&#xff01; 本文收錄于專欄&#xff1a;《2025華為OD真題目錄全流程解析/備考攻略/經驗…

騰訊一面面經:總結一下

1. Java 中的 和 equals 有什么區別&#xff1f;比較對象時使用哪一個 1. 操作符&#xff1a; 用于比較對象的內存地址&#xff08;引用是否相同&#xff09;。 對于基本數據類型、 比較的是值。&#xff08;8種基本數據類型&#xff09;對于引用數據類型、 比較的是兩個引…

計算機網絡中的DHCP是什么呀? 詳情解答

目錄 DHCP 是什么&#xff1f; DHCP 的工作原理 主要功能 DHCP 與網絡安全的關系 1. 正面作用 2. 潛在安全風險 DHCP 的已知漏洞 1. 協議設計缺陷 2. 軟件實現漏洞 3. 配置錯誤導致的漏洞 4. 已知漏洞總結 舉例說明 DHCP 與網絡安全 如何提升 DHCP 安全性 總結 D…