前端計算機視覺:使用 OpenCV.js 在瀏覽器中實現圖像處理

一、OpenCV.js 簡介與環境搭建

OpenCV(Open Source Computer Vision Library)是一個強大的計算機視覺庫,廣泛應用于圖像和視頻處理領域。傳統上,OpenCV 主要在后端使用 Python 或 C++ 等語言。但隨著 WebAssembly (Wasm) 技術的發展,OpenCV 也有了 JavaScript 版本 ——OpenCV.js,它可以直接在瀏覽器中高效運行,為前端開發者提供了前所未有的計算機視覺能力。

1.1 引入 OpenCV.js

在瀏覽器中使用 OpenCV.js 有多種方式,最簡單的是通過 CDN 引入:

<script async src="https://docs.opencv.org/4.5.5/opencv.js" onload="onOpenCvReady();" type="text/javascript"></script>

這種方式適合快速測試和開發。另一種方式是將 OpenCV.js 下載到本地項目中:

npm install @techstark/opencv-js

然后在 HTML 中引入:

<script async src="node_modules/@techstark/opencv-js/opencv.js" onload="onOpenCvReady();" type="text/javascript"></script>

1.2 初始化與加載檢查

由于 OpenCV.js 是一個較大的庫,需要異步加載。我們可以通過以下方式確保庫加載完成后再執行相關代碼:

function onOpenCvReady() {document.getElementById('status').innerHTML = 'OpenCV.js 已加載完成';// 在這里開始使用 OpenCV.jscvVersion = cv.getVersion();console.log('OpenCV 版本:', cvVersion);
}

在 HTML 中添加狀態顯示元素:

<body><div id="status">正在加載 OpenCV.js...</div><!-- 其他頁面內容 -->
</body>

二、基本圖像處理操作

2.1 圖像讀取與顯示

OpenCV.js 主要處理 cv.Mat 對象(矩陣),這是存儲圖像數據的核心結構。下面是一個從 HTML Image 元素讀取圖像并顯示的完整示例:

<!DOCTYPE html>
<html>
<head><title>OpenCV.js 圖像讀取與顯示示例</title><script async src="https://docs.opencv.org/4.5.5/opencv.js" onload="onOpenCvReady();" type="text/javascript"></script><style>.container {display: flex;flex-direction: column;align-items: center;margin-top: 20px;}.canvas-container {display: flex;gap: 20px;margin-top: 20px;}canvas {border: 1px solid #ccc;}</style>
</head>
<body><div class="container"><h2>OpenCV.js 圖像讀取與顯示</h2><div id="status">正在加載 OpenCV.js...</div><img id="imageSrc" src="example.jpg" alt="示例圖片" crossorigin="anonymous" style="display: none;"><div class="canvas-container"><div><p>原始圖像</p><canvas id="inputCanvas"></canvas></div><div><p>處理后圖像</p><canvas id="outputCanvas"></canvas></div></div></div><script>let src, dst, inputCanvas, outputCanvas;function onOpenCvReady() {document.getElementById('status').innerHTML = 'OpenCV.js 已加載完成';// 初始化畫布和圖像矩陣inputCanvas = document.getElementById('inputCanvas');outputCanvas = document.getElementById('outputCanvas');// 等待圖像加載完成const img = document.getElementById('imageSrc');img.onload = function() {// 設置畫布大小inputCanvas.width = img.width;inputCanvas.height = img.height;outputCanvas.width = img.width;outputCanvas.height = img.height;// 讀取圖像到 Mat 對象src = cv.imread(img);dst = new cv.Mat();// 在輸入畫布上顯示原始圖像cv.imshow(inputCanvas, src);// 示例:復制圖像到輸出畫布src.copyTo(dst);cv.imshow(outputCanvas, dst);// 釋放資源// 注意:在實際應用中,當不再需要 Mat 對象時應及時釋放// src.delete();// dst.delete();}// 如果圖像已經加載if (img.complete) {img.onload();}}</script>
</body>
</html>

這個示例展示了 OpenCV.js 的基本工作流程:加載圖像、創建 Mat 對象、處理圖像、顯示結果。需要注意的是,OpenCV.js 使用的內存需要手動管理,通過調用 delete () 方法釋放不再使用的 Mat 對象。

2.2 顏色空間轉換

顏色空間轉換是圖像處理中的常見操作。例如,將彩色圖像轉換為灰度圖像:

// 假設 src 是已經加載的彩色圖像
dst = new cv.Mat();
// 使用 COLOR_RGB2GRAY 標志進行轉換
cv.cvtColor(src, dst, cv.COLOR_RGB2GRAY);
// 顯示灰度圖像
cv.imshow(outputCanvas, dst);

也可以在不同的顏色空間之間進行轉換,比如從 RGB 到 HSV:

cv.cvtColor(src, dst, cv.COLOR_RGB2HSV);

2.3 圖像濾波

圖像濾波是平滑圖像、去除噪聲或增強特定特征的常用技術。以下是幾種常見的濾波操作:

2.3.1 高斯模糊
// 定義核大小,必須是奇數
let ksize = new cv.Size(5, 5);
// 定義標準差
let sigmaX = 0;
let sigmaY = 0;
cv.GaussianBlur(src, dst, ksize, sigmaX, sigmaY, cv.BORDER_DEFAULT);
2.3.2 中值濾波
// 定義核大小,必須是大于 1 的奇數
let ksize = 5;
cv.medianBlur(src, dst, ksize);
2.3.3 雙邊濾波
// 定義參數
let d = 9; // 過濾時使用的像素領域直徑
let sigmaColor = 75; // 顏色空間濾波器的sigma值
let sigmaSpace = 75; // 坐標空間中濾波器的sigma值
cv.bilateralFilter(src, dst, d, sigmaColor, sigmaSpace);

2.4 邊緣檢測

邊緣檢測是計算機視覺中的重要任務,常用于特征提取和圖像分割。

2.4.1 Canny 邊緣檢測
// 轉換為灰度圖像
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGB2GRAY);// 應用 Canny 邊緣檢測
let edges = new cv.Mat();
let threshold1 = 100;
let threshold2 = 200;
let apertureSize = 3;
let L2gradient = false;
cv.Canny(gray, edges, threshold1, threshold2, apertureSize, L2gradient);// 顯示結果
cv.imshow(outputCanvas, edges);// 釋放資源
gray.delete();
edges.delete();
2.4.2 Sobel 算子
// 轉換為灰度圖像
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGB2GRAY);// 創建輸出矩陣
let sobelx = new cv.Mat();
let sobely = new cv.Mat();
let abs_sobelx = new cv.Mat();
let abs_sobely = new cv.Mat();
let sobel_edges = new cv.Mat();// 計算 x 和 y 方向的梯度
cv.Sobel(gray, sobelx, cv.CV_16S, 1, 0, 3, 1, 0, cv.BORDER_DEFAULT);
cv.Sobel(gray, sobely, cv.CV_16S, 0, 1, 3, 1, 0, cv.BORDER_DEFAULT);// 轉換為 8 位無符號整數
cv.convertScaleAbs(sobelx, abs_sobelx);
cv.convertScaleAbs(sobely, abs_sobely);// 合并兩個方向的梯度
cv.addWeighted(abs_sobelx, 0.5, abs_sobely, 0.5, 0, sobel_edges);// 顯示結果
cv.imshow(outputCanvas, sobel_edges);// 釋放資源
gray.delete();
sobelx.delete();
sobely.delete();
abs_sobelx.delete();
abs_sobely.delete();
sobel_edges.delete();

三、特征提取與描述

3.1 Harris 角點檢測

角點是圖像中重要的局部特征,Harris 角點檢測是一種經典的角點檢測方法:

// 轉換為灰度圖像
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGB2GRAY);// 創建輸出矩陣
let dstHarris = new cv.Mat();
let dstNorm = new cv.Mat();
let dstNormScaled = new cv.Mat();// 應用 Harris 角點檢測
let blockSize = 2;
let apertureSize = 3;
let k = 0.04;
cv.cornerHarris(gray, dstHarris, blockSize, apertureSize, k, cv.BORDER_DEFAULT);// 歸一化結果
cv.normalize(dstHarris, dstNorm, 0, 255, cv.NORM_MINMAX, cv.CV_32FC1, new cv.Mat());
cv.convertScaleAbs(dstNorm, dstNormScaled);// 在原圖上繪制角點
for (let j = 0; j < dstNorm.rows; j++) {for (let i = 0; i < dstNorm.cols; i++) {if (parseInt(dstNorm.ptr(j, i)[0]) > 100) {cv.circle(dstNormScaled, new cv.Point(i, j), 5, [0, 255, 0], 2, 8, 0);}}
}// 顯示結果
cv.imshow(outputCanvas, dstNormScaled);// 釋放資源
gray.delete();
dstHarris.delete();
dstNorm.delete();
dstNormScaled.delete();

3.2 ORB (Oriented FAST and Rotated BRIEF)

ORB 是一種結合了 FAST 特征點檢測和 BRIEF 特征描述子的高效特征提取方法:

// 轉換為灰度圖像
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGB2GRAY);// 創建 ORB 檢測器
let orb = new cv.ORB();// 檢測關鍵點并計算描述符
let keypoints = new cv.KeyPointVector();
let descriptors = new cv.Mat();
orb.detectAndCompute(gray, new cv.Mat(), keypoints, descriptors);// 在原圖上繪制關鍵點
let output = new cv.Mat();
cv.cvtColor(gray, output, cv.COLOR_GRAY2BGR);
cv.drawKeypoints(gray, keypoints, output, [0, 255, 0], 0);// 顯示結果
cv.imshow(outputCanvas, output);// 釋放資源
gray.delete();
orb.delete();
keypoints.delete();
descriptors.delete();
output.delete();

四、圖像分割

4.1 閾值分割

閾值分割是最簡單的圖像分割方法,根據像素值與閾值的比較將圖像分為不同區域:

// 轉換為灰度圖像
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGB2GRAY);// 應用閾值分割
let dst = new cv.Mat();
let thresholdValue = 127;
let maxValue = 255;
let thresholdType = cv.THRESH_BINARY;
cv.threshold(gray, dst, thresholdValue, maxValue, thresholdType);// 顯示結果
cv.imshow(outputCanvas, dst);// 釋放資源
gray.delete();
dst.delete();

4.2 自適應閾值分割

自適應閾值分割根據像素周圍區域的局部特性計算閾值,適合處理光照不均勻的圖像:

// 轉換為灰度圖像
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGB2GRAY);// 應用自適應閾值分割
let dst = new cv.Mat();
let maxValue = 255;
let adaptiveMethod = cv.ADAPTIVE_THRESH_GAUSSIAN_C;
let thresholdType = cv.THRESH_BINARY;
let blockSize = 11;
let C = 2;
cv.adaptiveThreshold(gray, dst, maxValue, adaptiveMethod, thresholdType, blockSize, C);// 顯示結果
cv.imshow(outputCanvas, dst);// 釋放資源
gray.delete();
dst.delete();

4.3 基于輪廓的分割

輪廓檢測可以識別圖像中的連續區域,常用于物體分割:

// 轉換為灰度圖像
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGB2GRAY);// 應用閾值處理
let thresh = new cv.Mat();
cv.threshold(gray, thresh, 127, 255, cv.THRESH_BINARY);// 查找輪廓
let contours = new cv.MatVector();
let hierarchy = new cv.Mat();
cv.findContours(thresh, contours, hierarchy, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE);// 在原圖上繪制輪廓
let drawing = cv.Mat.zeros(thresh.size(), cv.CV_8UC3);
for (let i = 0; i < contours.size(); i++) {let color = new cv.Scalar(Math.random() * 255, Math.random() * 255, Math.random() * 255);cv.drawContours(drawing, contours, i, color, 2, cv.LINE_8, hierarchy, 0);
}// 顯示結果
cv.imshow(outputCanvas, drawing);// 釋放資源
gray.delete();
thresh.delete();
contours.delete();
hierarchy.delete();
drawing.delete();

五、視頻處理

OpenCV.js 也可以處理視頻流,包括攝像頭實時視頻。以下是一個簡單的視頻處理示例:

<!DOCTYPE html>
<html>
<head><title>OpenCV.js 視頻處理示例</title><script async src="https://docs.opencv.org/4.5.5/opencv.js" onload="onOpenCvReady();" type="text/javascript"></script><style>.container {display: flex;flex-direction: column;align-items: center;margin-top: 20px;}.video-container {display: flex;gap: 20px;margin-top: 20px;}video, canvas {border: 1px solid #ccc;width: 640px;height: 480px;}button {margin-top: 10px;padding: 10px 20px;font-size: 16px;}</style>
</head>
<body><div class="container"><h2>OpenCV.js 視頻處理</h2><div id="status">正在加載 OpenCV.js...</div><div class="video-container"><div><p>原始視頻</p><video id="inputVideo" autoplay muted playsinline></video></div><div><p>處理后視頻</p><canvas id="outputCanvas"></canvas></div></div><button id="startButton">開始</button><button id="stopButton" disabled>停止</button></div><script>let video, outputCanvas, outputContext;let src, dst, gray;let processing = false;let requestId;function onOpenCvReady() {document.getElementById('status').innerHTML = 'OpenCV.js 已加載完成';video = document.getElementById('inputVideo');outputCanvas = document.getElementById('outputCanvas');outputContext = outputCanvas.getContext('2d');// 獲取攝像頭訪問權限navigator.mediaDevices.getUserMedia({ video: true, audio: false }).then(function(stream) {video.srcObject = stream;video.onloadedmetadata = function(e) {video.play();document.getElementById('startButton').disabled = false;};}).catch(function(err) {console.error('攝像頭訪問錯誤: ' + err);document.getElementById('status').innerHTML = '無法訪問攝像頭';});// 按鈕事件處理document.getElementById('startButton').addEventListener('click', startProcessing);document.getElementById('stopButton').addEventListener('click', stopProcessing);}function startProcessing() {if (processing) return;// 初始化 OpenCV 矩陣src = new cv.Mat(video.height, video.width, cv.CV_8UC4);dst = new cv.Mat(video.height, video.width, cv.CV_8UC4);gray = new cv.Mat(video.height, video.width, cv.CV_8UC1);processing = true;document.getElementById('startButton').disabled = true;document.getElementById('stopButton').disabled = false;// 開始處理視頻幀processVideo();}function stopProcessing() {if (!processing) return;processing = false;document.getElementById('startButton').disabled = false;document.getElementById('stopButton').disabled = true;// 釋放資源if (src) src.delete();if (dst) dst.delete();if (gray) gray.delete();// 取消動畫幀請求if (requestId) {cancelAnimationFrame(requestId);}}function processVideo() {if (!processing) return;try {// 從視頻幀讀取數據到 srccv.imread(video, src);// 示例處理:轉換為灰度圖cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY);cv.cvtColor(gray, dst, cv.COLOR_GRAY2RGBA);// 在處理后的幀上繪制文字let text = 'OpenCV.js 視頻處理';let org = new cv.Point(10, 30);let fontFace = cv.FONT_HERSHEY_SIMPLEX;let fontScale = 1;let color = new cv.Scalar(255, 0, 0, 255);let thickness = 2;cv.putText(dst, text, org, fontFace, fontScale, color, thickness);// 將處理結果顯示在 canvas 上cv.imshow(outputCanvas, dst);// 繼續處理下一幀requestId = requestAnimationFrame(processVideo);} catch (err) {console.error('處理視頻幀時出錯:', err);stopProcessing();}}</script>
</body>
</html>

這個示例展示了如何捕獲攝像頭視頻流并使用 OpenCV.js 進行實時處理。你可以根據需要修改 processVideo 函數中的處理邏輯,實現更復雜的視頻處理效果。

六、實際應用案例

6.1 實時人臉檢測

結合 OpenCV.js 和 Haar 級聯分類器,可以實現瀏覽器中的實時人臉檢測:

// 加載人臉檢測模型
let faceCascade = new cv.CascadeClassifier();
let utils = new Utils('errorMessage');// 加載預訓練的人臉檢測模型
utils.createFileFromUrl('haarcascade_frontalface_default.xml','haarcascade_frontalface_default.xml',() => {faceCascade.load('haarcascade_frontalface_default.xml');document.getElementById('status').innerHTML = '人臉檢測模型已加載';},() => {document.getElementById('status').innerHTML = '模型加載失敗';});// 在視頻處理循環中添加人臉檢測邏輯
function processVideo() {if (!processing) return;try {// 從視頻幀讀取數據到 srccv.imread(video, src);// 轉換為灰度圖以提高檢測速度cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY);// 檢測人臉let faces = new cv.RectVector();let msize = new cv.Size(0, 0);// 檢測參數:scaleFactor=1.1, minNeighbors=3, flags=0, minSize=msizefaceCascade.detectMultiScale(gray, faces, 1.1, 3, 0, msize);// 在原圖上繪制檢測到的人臉for (let i = 0; i < faces.size(); i++) {let face = faces.get(i);let point1 = new cv.Point(face.x, face.y);let point2 = new cv.Point(face.x + face.width, face.y + face.height);cv.rectangle(src, point1, point2, [255, 0, 0, 255], 2);}// 顯示結果cv.imshow(outputCanvas, src);// 釋放資源faces.delete();// 繼續處理下一幀requestAnimationFrame(processVideo);} catch (err) {console.error('處理視頻幀時出錯:', err);stopProcessing();}
}

6.2 圖像匹配

使用 OpenCV.js 進行圖像匹配,可以在一個圖像中查找另一個圖像的位置:

// 加載源圖像和模板圖像
let src = cv.imread('sourceImage');
let templ = cv.imread('templateImage');// 創建結果矩陣
let result = new cv.Mat();
let result_cols = src.cols - templ.cols + 1;
let result_rows = src.rows - templ.rows + 1;
result.create(result_rows, result_cols, cv.CV_32FC1);// 應用模板匹配
let method = cv.TM_CCOEFF_NORMED;
cv.matchTemplate(src, templ, result, method);// 找到最佳匹配位置
let minMaxLoc = cv.minMaxLoc(result);
let matchLoc;
if (method === cv.TM_SQDIFF || method === cv.TM_SQDIFF_NORMED) {matchLoc = minMaxLoc.minLoc;
} else {matchLoc = minMaxLoc.maxLoc;
}// 在原圖上繪制匹配區域
let point1 = new cv.Point(matchLoc.x, matchLoc.y);
let point2 = new cv.Point(matchLoc.x + templ.cols, matchLoc.y + templ.rows);
cv.rectangle(src, point1, point2, [0, 255, 0, 255], 2);// 顯示結果
cv.imshow('outputCanvas', src);// 釋放資源
src.delete();
templ.delete();
result.delete();

七、性能優化與最佳實踐

7.1 內存管理

在使用 OpenCV.js 時,正確的內存管理非常重要。每個 cv.Mat 對象都占用內存,不再使用時應調用 delete () 方法釋放:

// 創建 Mat 對象
let mat = new cv.Mat();// 使用 mat 對象進行各種操作// 不再使用時釋放內存
mat.delete();

對于在循環中創建的臨時 Mat 對象,更要特別注意及時釋放,避免內存泄漏。

7.2 異步處理

對于復雜的圖像處理任務,考慮使用 Web Workers 進行異步處理,避免阻塞主線程:

// main.js
// 創建 Web Worker
const worker = new Worker('worker.js');// 發送圖像數據到 worker
worker.postMessage({ imageData: imageData }, [imageData.data.buffer]);// 接收處理結果
worker.onmessage = function(e) {// 在 canvas 上顯示處理結果outputContext.putImageData(e.data.processedImageData, 0, 0);
};// worker.js
self.onmessage = function(e) {// 加載 OpenCV.jsimportScripts('https://docs.opencv.org/4.5.5/opencv.js');self.cv['onRuntimeInitialized'] = function() {// 處理圖像let src = cv.matFromImageData(e.data.imageData);let dst = new cv.Mat();// 執行圖像處理操作cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY);// 轉換回 ImageDatalet imageData = new ImageData(new Uint8ClampedArray(dst.data),dst.cols,dst.rows);// 發送結果回主線程self.postMessage({ processedImageData: imageData }, [imageData.data.buffer]);// 釋放資源src.delete();dst.delete();};
};

7.3 優化處理參數

對于計算密集型操作,如特征檢測或視頻處理,可以通過調整參數來平衡性能和精度:

// 調整 Canny 邊緣檢測參數以提高性能
let threshold1 = 100;
let threshold2 = 200;
let apertureSize = 3; // 可以增大以減少計算量
let L2gradient = false; // 使用更簡單的梯度計算方法
cv.Canny(src, dst, threshold1, threshold2, apertureSize, L2gradient);

八、局限性與挑戰

盡管 OpenCV.js 提供了強大的功能,但在前端使用仍有一些局限性:

  1. 性能限制:WebAssembly 雖然比純 JavaScript 快得多,但對于復雜的計算機視覺任務,仍然可能比原生實現慢。

  2. 內存管理:與原生 OpenCV 相比,JavaScript 環境中的內存管理更加復雜,需要開發者手動釋放資源。

  3. 模型加載:預訓練模型(如 Haar 級聯分類器)體積較大,加載時間較長。

  4. 瀏覽器兼容性:不同瀏覽器對 WebAssembly 和 OpenCV.js 的支持程度可能不同。

  5. 長時間運行任務:長時間運行的計算密集型任務可能導致頁面無響應,需要使用 Web Workers 進行優化。

九、總結與未來展望

OpenCV.js 為前端開發者打開了計算機視覺的大門,使我們能夠在瀏覽器中實現圖像和視頻處理功能,而無需依賴后端服務。從簡單的圖像處理到復雜的實時視頻分析,OpenCV.js 提供了豐富的功能和工具。

隨著 WebAssembly 技術的不斷發展和瀏覽器性能的提升,我們可以期待 OpenCV.js 在未來會有更好的表現和更廣泛的應用場景。例如,增強現實 (AR)、實時視頻編輯、智能監控等領域都可能受益于 OpenCV.js 的發展。

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

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

相關文章

開發在線商店:基于Vue2+ElementUI的電商平臺前端實踐

Hi&#xff0c;我是布蘭妮甜 &#xff01;在當今數字化時代&#xff0c;電子商務已成為商業領域的重要組成部分。開發一個功能完善、用戶友好的在線商店應用對于企業拓展市場至關重要。本文將詳細介紹如何使用Vue2框架配合ElementUI組件庫開發一個完整的在線商店應用。 文章目錄…

vue3 隨手筆記9--組件通信方式9/2--自定義事件

一、什么是自定義事件&#xff1f; 自定義事件是 Vue 組件間通信的一種機制。子組件通過 this.$emit(事件名, 數據) 觸發一個事件。父組件監聽這個事件并執行相應的邏輯。 二、基本使用 準備工作 demo 繼續使用筆記8中的 鏈接為demo 在views文件夾下 創建新的文件夾為cust…

深入理解Reactor調試模式:Hooks.onOperatorDebug() vs ReactorDebugAgent.init()

在現代Java開發中&#xff0c;調試Reactor流是確保應用程序性能和穩定性的關鍵步驟。Reactor調試模式提供了多種初始化方法&#xff0c;其中最常用的兩種是Hooks.onOperatorDebug()和ReactorDebugAgent.init()。本文將深入探討這兩種方法的區別&#xff0c;幫助開發者選擇最適合…

QT6 源(151)模型視圖架構里的表格窗體視圖 QTableWidget 篇一:先學習倆屬性以及 public 權限的公共成員函數,

&#xff08;1&#xff09;本篇的內容因為是子類&#xff0c;內容較視圖基類簡單了一些。又因為時間緊迫&#xff0c;不再詳細舉例了。詳細的測試可以滿足好奇心&#xff0c;也可以增強寫代碼的自信心。奈何時間不夠。不完美&#xff0c;就不完美了。以后有機會&#xff0c;再補…

ffmpeg 下載、安裝、配置、基本語法、避坑指南(覆蓋 Windows、macOS、Linux 平臺)

ffmpeg 下載、安裝、配置、基本語法、避坑指南&#xff08;覆蓋 Windows、macOS、Linux 平臺&#xff09; 本文是一篇面向初學者的超詳細 FFmpeg 教程&#xff0c;包括 FFmpeg 下載、安裝、配置、基本語法 與 避坑指南。覆蓋 Windows、macOS、Linux 平臺的安裝方式與 環境變量…

Kotlin 安裝使用教程

一、Kotlin 簡介 Kotlin 是 JetBrains 開發的一種現代、靜態類型的編程語言&#xff0c;完全兼容 Java&#xff0c;主要應用于 Android 開發、后端服務開發、前端 Web 開發&#xff08;Kotlin/JS&#xff09;和多平臺開發&#xff08;Kotlin Multiplatform&#xff09;。 二、…

day08-Elasticsearch

黑馬商城作為一個電商項目&#xff0c;商品的搜索肯定是訪問頻率最高的頁面之一。目前搜索功能是基于數據庫的模糊搜索來實現的&#xff0c;存在很多問題。 首先&#xff0c;查詢效率較低。 由于數據庫模糊查詢不走索引&#xff0c;在數據量較大的時候&#xff0c;查詢性能很…

transformers 筆記:自定義模型(配置+模型+注冊為AutoCLass+本地保存加載)

Transformers 模型設計上是可定制的。每個模型的代碼都包含在 Transformers 倉庫的 model 子文件夾中&#xff08;transformers/src/transformers/models at main huggingface/transformers&#xff09;&#xff0c;每個模型文件夾通常包含&#xff1a; modeling.py&#xff1…

Java工具類,對象List提取某個屬性為List,對象List轉為對象Map其中某個屬性作為Key值

Java工具類package org.common;import lombok.extern.slf4j.Slf4j;import java.util.*; import java.util.stream.Collectors;Slf4j public final class CollectorHelper {/*** param element* param propertyName* param <E>* return*/public static <E> List toL…

ATE FT ChangeKit學習總結-20250630

目錄 一、基本概念 二、主要特點 三、BOM LIST Shuttle Hot Plate Dock Plate Contactor 四、設計要點 五、參考文獻與鏈接 一、基本概念 Change Kit在半導體封裝測試領域中是一個重要的組件,它作為Handler(自動化分類機)的配套治具,在芯片測試過程中發揮著關鍵作…

【網絡協議安全】任務14:路由器DHCP_AAA_TELNET配置

本文檔將詳細介紹在華為 eNSP 仿真環境中&#xff0c;實現路由器 DHCP 服務器功能、AAA 認證以及 TELNET 遠程登錄配置的完整步驟&#xff0c;適用于華為 VRP 系統路由器。 一、配置目標 路由器作為 DHCP 服務器&#xff0c;為局域網內的設備自動分配 IP 地址、子網掩碼、網關…

深度探索:現代翻譯技術的核心算法與實踐(第一篇)

引言:翻譯技術的演進之路 從早期的基于規則的機器翻譯(RBMT)到統計機器翻譯(SMT),再到如今主導行業的神經機器翻譯(NMT),翻譯技術已經走過了漫長的發展道路。現代翻譯系統不僅能夠處理簡單的句子,還能理解上下文、識別領域術語,甚至捕捉微妙的文化差異。 本系列文章將帶…

玩轉Docker | 使用Docker部署NotepadMX筆記應用程序

玩轉Docker | 使用Docker部署NotepadMX筆記應用程序 前言一、NotepadMX介紹工具簡介主要特點二、系統要求環境要求環境檢查Docker版本檢查檢查操作系統版本三、部署NotepadMX服務下載NotepadMX鏡像編輯部署文件創建容器檢查容器狀態檢查服務端口安全設置四、訪問NotepadMX服務訪…

Web前端:not(否定偽類選擇器)

not&#xff08;否定偽類選擇器&#xff09;CSS中的 :not() 選擇器是?個否定偽類選擇器&#xff0c;它?于選擇不符合給定選擇器的元素。這是?種排除特定元素的?法&#xff0c;可以?來簡 化復雜的選擇器&#xff0c;提? CSS 規則的靈活性和精確性。:not() 選擇器的基本語法…

【BTC】比特幣網絡

目錄 一、比特幣網絡架構 1.1 節點加入與離開 二、消息傳播方式 三、交易處理機制 四、網絡傳播問題 五、實際應用問題及解決 本章節講比特幣網絡的工作原理&#xff0c;講解新創建的區塊是如何在比特幣網絡中傳播的。 一、比特幣網絡架構 比特幣工作在應用層&#xff…

Clickhouse 的歷史發展過程

20.5.3 開始支持多線程20.6.3 支持explainmysql 20.8 實時同步mysql&#x1f4cc; ?一、早期版本階段&#xff08;1.1.x系列&#xff09;??版本范圍?&#xff1a;1.1.54245&#xff08;2017-07&#xff09;→ 1.1.54394&#xff08;2018-07&#xff09;?核心特性?&#x…

玩轉n8n工作流教程(一):Windows系統本地部署n8n自動化工作流(n8n中文漢化)

在Windows系統下使用 Docker 本地部署N8N中文版的具體操作&#xff0c;進行了詳盡闡述&#xff0c;玩轉n8n工作流教程系列內容旨在手把手助力從0開始一步一步深入學習n8n工作流。想研究n8n工作流自動化的小伙伴們可以加個關注一起學起來。后續也會持續分享n8n自動化工作流各種玩…

mini-program01の系統認識微信小程序開發

一、官方下載并安裝 1、下載&#xff08;I選了穩定版&#xff09; https://developers.weixin.qq.com/miniprogram/dev/devtools/download.htmlhttps://developers.weixin.qq.com/miniprogram/dev/devtools/download.html 2、安裝&#xff08;A FEW MOMENT LATER&#xff09;…

如何將 Java 項目打包為可執行 JAR 文件

如何將 Java 項目打包為可執行 JAR 文件我將詳細介紹將 Java 項目打包為可執行 JAR 文件的完整流程&#xff0c;包括使用 IDE 和命令行兩種方法。方法一&#xff1a;使用 IntelliJ IDEA 打包步驟 1&#xff1a;配置項目結構打開項目點擊 File > Project Structure在 Project…

【Starrocks 異常解決】-- mysql flink sync to starrocks row error

1、異常信息 flink 1.20 starrocks 3.3.0 mysql 8.0 errorLog: Error: Target column count: 35 doesnt match source value column count: 28. Column separator: \t, Row delimiter: \n. Row: 2025-05-22 6 23400055 214 dssd 1 1 1928 mm2er 360 20000.00000000 1…