1.效果图片
2.下载opencv.js
比如下载 4.5.0 版本的 opencv.js 文件
https://docs.opencv.org/4.5.0/opencv.js
3.引入
opencv.js放在static文件夹下
页面中引入
let cv = require('../../static/opencv/opencv.js');
4.进入正题
//页面先放一个隐藏图片
//获取图片
var imgSrcElement = document.getElementById('imageUrl');
//读取图片,将彩色图转为灰度图 let img = cv.imread(imgSrcElement)
let gray = new cv.Mat(); cv.cvtColor(img, gray, cv.COLOR_RGBA2GRAY);
const binary = new cv.Mat(); cv.threshold(gray, binary, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU);
//高斯模糊去除噪点 let blur = new cv.Mat(); cv.GaussianBlur(gray, blur, new cv.Size(5, 5), 0, 0, cv.BORDER_DEFAULT);
//边缘检测,使用
let edges = new cv.Mat(); cv.Canny(blur, edges, 50, 150, 3, false);
//查找轮廓 const contours = new cv.MatVector(); const hierarchy = new cv.Mat(); cv.findContours(edges, contours, hierarchy, cv.RETR_EXTERNAL, cv .CHAIN_APPROX_SIMPLE);
//计算最大面积 let maxContourIndex = -1; let maxContourArea = 0; for (let i = 0; i < contours.size(); i++) { const contourArea = cv.contourArea(contours.get(i)); if (contourArea > maxContourArea) { maxContourIndex = i; maxContourArea = contourArea; } }
const contour = contours.get(maxContourIndex ); const area = cv.contourArea(contour); const perimeter = cv.arcLength(contour, true); const approx = new cv.Mat(); // 近似轮廓 cv.approxPolyDP(contour, approx, 0.02 * perimeter, true);
const rect1 = cv.minAreaRect(contour); const vertices = cv.RotatedRect.points(rect1);
// 获取提取纸张的四个坐标点 const corners = []; for (let i = 0; i < vertices.length; ++i) { corners.push({ x: vertices[i].x, y: vertices[i].y }); } console.log("输出新坐标1", corners) this.newPint = corners // 矩形的四个顶点坐标 const pints = [{ x: this.newPint[0].x, y: this.newPint[0].y }, //左上角 { x: this.newPint[1].x, y: this.newPint[1].y }, //右上角 { x: this.newPint[2].x, y: this.newPint[2].y }, //右下角 { x: this.newPint[3].x, y: this.newPint[3].y } //左下角 ];
//显示图片(效果测试) // document.getElementsByTagName("canvas")[0].setAttribute("id", // "canvas1"); // cv.imshow('canvas1', img);
const ctx = uni.createCanvasContext('canvas', this); //先清除上一次的 ctx.clearRect(0, 0, this.innerWidth, this .innerHeight - 360); // 绘制图片 ctx.drawImage(res.tempFilePaths[0], 0, 0, this.innerWidth, this .innerHeight - 360); // 创建蒙层 ctx.fillStyle = 'rgba(0, 0, 0, 0.4)'; ctx.fillRect(0, 0, this.innerWidth, this .innerHeight - 360); // 设置蒙层混合模式 ctx.globalCompositeOperation = 'destination-out'; ctx.beginPath(); for (let i = 0; i < pints.length; i++) { const screenX = pints[i].x * $this.innerWidth / img .cols; const screenY = pints[i].y * ($this.innerHeight - 360) / img .rows; if (i === 0) { ctx.moveTo(screenX, screenY); } else { ctx.lineTo(screenX, screenY); } } ctx.closePath(); // 描边路径 ctx.stroke(); // 使用反向路径绘制,将未连接线外的区域作为裁剪区域 ctx.globalCompositeOperation = 'destination-out'; // 填充路径 ctx.fillStyle = "rgba(255,255,255,0.2)"; // 设置填充颜色 ctx.fill();
//填充节点颜色 for (let i = 0; i < pints.length; i++) { ctx.beginPath(); //计算屏幕坐标 const screenX = pints[i].x * $this.innerWidth / img .cols; const screenY = pints[i].y * ($this.innerHeight - 360) / img .rows; let temp = {} temp.x = screenX temp.y = screenY $this.pintList.push(temp) ctx.arc(screenX, screenY, 6, 0, 2 * Math .PI);
// 绘制圆 参数依次为 圆的横坐标/纵坐标/半径/绘制圆的起始位置/绘制圆的弧度大小 ctx.closePath(); ctx.stroke(); ctx.fill(); } ctx.globalCompositeOperation = 'source-over'; // 恢复默认混合模式 ctx.draw(); approx.delete(); } }
推荐阅读
发表评论