如何解决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);
为了解决这个问题,我进行了以下改进:
- 设置 canvas 大小:在图像加载完成后,即在 imgelement.onload 函数中,设置 canvas 的宽度和高度与图像的尺寸一致。
- 添加错误处理:在图像加载失败时,即在 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