如何解決OpenCV.js投影變換后結果為空白透明圖片的問題?

如何解決opencv.JS投影變換結果為空白的透明圖片問題

在使用opencv.js進行圖像處理時,有時候會遇到投影變換后圖像結果為空白的透明圖片的問題。以下是我遇到的問題以及解決方法

我在處理圖像時,代碼能夠成功識別出文檔的四個坐標,但到了投影變換這一步,得到的結果總是空白的透明圖片,并且沒有報錯。以下是我使用的投影變換部分代碼:

// 投影變換 let srcquad = cv.matfromarray(4, 1, cv.cv_32fc2, points.flat()); let dstquad = cv.matfromarray(4, 1, cv.cv_32fc2, [0, 0, img.cols, 0, img.cols, img.rows, 0, img.rows]); let transmtx = cv.getperspectivetransform(srcquad, dstquad); let target = new cv.mat(); cv.warpperspective(img, target, transmtx, new cv.size(img.cols, img.rows)); // 顯示結果 cv.imshow(canvas, target);

為了解決這個問題,我進行了以下改進:

  1. 設置 canvas 大小:在圖像加載完成后,即在 imgelement.onload 函數中,設置 canvas 的寬度和高度與圖像的尺寸一致。
  2. 添加錯誤處理:在圖像加載失敗時,即在 imgelement.onerror 函數中,添加錯誤處理以捕獲圖像加載錯誤。

以下是改進后的完整代碼:

<html lang="en"> <head>     <meta charset="UTF-8">     <meta name="viewport" content="width=device-width, initial-scale=1.0">     <title>OpenCV.js Example</title> </head> <body>     <script async src="https://docs.opencv.org/4.5.5/opencv.js" onload="onOpenCvReady();"></script>     <canvas id="canvasOutput"></canvas>     <script>         function onOpenCvReady() {             console.log("OpenCV.js加載完成.");             processImage();         }          function sleep(ms) {             return new Promise(resolve => setTimeout(resolve, ms));         }          async function processImage() {             await sleep(3000); // 等待 3 秒             let imageUrl = "../archives/111.jpg";             let imgElement = new Image();             imgElement.src = imageUrl;             var img;              // 加載圖像             imgElement.onload = function() {                 try {                     img = cv.imread(imgElement);                     if (img.empty()) {                         console.error("Image could not be read.");                         return;                     }                      // 獲取 canvas 元素并設置大小                     let canvas = document.getElementById('canvasOutput');                     canvas.width = img.cols;                     canvas.height = img.rows;                      // 重置圖像大小                     let dsize = new cv.Size(img.cols, img.rows);                     let dst = new cv.Mat();                     cv.resize(img, dst, dsize, 0, 0, cv.INTER_AREA);                      // 轉為灰度圖像                     console.log("轉換之前:", img);                     let gray = new cv.Mat(); // 創建一個新的 Mat 對象來存灰度圖像                     cv.cvtColor(dst, gray, cv.COLOR_BGR2GRAY); // 使用適當的轉換                     console.log("轉換之后:", gray);                      // 高斯濾波                     cv.GaussianBlur(gray, gray, new cv.Size(11, 11), 0, 0);                     cv.imshow(canvas, gray);                     cv.Canny(gray, gray, 20, 50, 3);                      let contours = new cv.MatVector();                     let hierarchy = new cv.Mat();                     cv.findContours(gray, contours, hierarchy, cv.RETR_CCOMP, cv.CHAIN_APPROX_NONE);                      let index = 0, maxArea = 0;                     const area = img.cols * img.rows;                     for (let i = 0; i < contours.size(); ++i) {                         let tempArea = Math.abs(cv.contourArea(contours.get(i)));                         if (tempArea > maxArea && tempArea > 0.3 * area) {                             index = i;                             maxArea = tempArea;                         }                     }                      if (maxArea === 0) return;                     const foundContour = contours.get(index);                     const arcL = cv.arcLength(foundContour, true);                     let approx = new cv.Mat();                      // 逼近多邊形                     cv.approxPolyDP(foundContour, approx, 0.01 * arcL, true);                      if (approx.total() === 4) {                         let points = [];                         const data32S = approx.data32S;                         for (let i = 0, len = data32S.length / 2; i < len; i++) {                             points[i] = {x: data32S[i * 2], y: data32S[i * 2 + 1]};                         }                         console.log("檢測到四邊形點:", points);                          // 投影變換                         let srcQuad = cv.matFromArray(4, 1, cv.CV_32FC2, points.flat());                         let dstQuad = cv.matFromArray(4, 1, cv.CV_32FC2, [0, 0, img.cols, 0, img.cols, img.rows, 0, img.rows]);                         let transmtx = cv.getPerspectiveTransform(srcQuad, dstQuad);                         let target = new cv.Mat();                         cv.warpPerspective(img, target, transmtx, new cv.Size(img.cols, img.rows));                          // 顯示結果                         cv.imshow(canvas, target);                          // 創建一個臨時的 canvas 元素                         let tempCanvas = document.createElement('canvas');                         tempCanvas.width = target.cols;                         tempCanvas.height = target.rows;                         let tempCtx = tempCanvas.getContext('2d');                          // 將 cv.Mat 轉換為 ImageData                         let imageData = new ImageData(new Uint8ClampedArray(target.data), target.cols, target.rows);                          // 將 ImageData 繪制到臨時的 canvas 上                         tempCtx.putImageData(imageData, 0, 0);                          // 將 canvas 生成 Blob 對象                         tempCanvas.toBlob((blob) => {                             // 創建一個 URL 對象                             let url = URL.createObjectURL(blob);                             // 創建一個 a 元素并設置其屬性                             let a = document.createElement('a');                             a.href = url;                             a.download = 'processed_image.png'; // 設置下載文件的名稱                             // 將 a 元素添加到 body 中                             document.body.appendChild(a);                             // 觸發點擊事件以開始下載                             a.click();                             // 下載完成后移除 a 元素                             document.body.removeChild(a);                             // 釋放 URL 對象                             URL.revokeObjectURL(url);                         }, 'image/png');                          // 釋放內存                         target.delete(); // 在這里釋放 target,否則會造成內存泄露                     }                      // 釋放內存                     img.delete();                     dst.delete();                     gray.delete(); // 釋放灰度圖像 Mat                     contours.delete();                     hierarchy.delete();                     approx.delete();                     foundContour.delete();                 } catch (err) {                     console.error("圖像處理出現錯誤:", err);                 }             }              imgElement.onerror = function() {                 console.error("Image could not be loaded.");             };         }     </script> </body> </html>

通過上述改進,我成功解決了投影變換后結果為空白透明圖片的問題。希望這些改進對大家也有幫助。

? 版權聲明
THE END
喜歡就支持一下吧
點贊8 分享