当前位置: 首页 > news >正文

js应用opencv

1.引用import cv from ‘@techstark/opencv-js’;
2.vue代码

 <div class="historyLeft2"><div style="relative: display" v-for="(item, index) in dataReturns3"><el-row><el-col :span="16"><canvas v-if="index === 0" ref="myCanvas" width="230" height="230"></canvas></el-col><el-col :span="8" style="text-align: left;"><el-buttonv-if="tiancongflag==0"type="success" style="margin-top:10px; margin-left:15px; font-size:14px;"size="small"@click="tiancong"round>填充缺陷</el-button><el-buttonv-if="tiancongflag === 1"type="warning" style="margin-top:10px;margin-left:15px;font-size:14px;"size="small"@click="tiancong"round>取消填充</el-button></el-col></el-row></div></div>

3.js代码

 processBase64Image(base64Data) {const img = new Image();img.onload = () => {if(this.tiancongflag == 1){this.processImage(img);}else{this.processImage2(img);}};console.log(444)img.src = base64Data;},processImage(img) {console.log(img)this.$nextTick(() => {const canvas = this.$refs.myCanvas;const ctx = canvas[0].getContext('2d');var canvasWidth = canvas[0].width;var canvasHeight = canvas[0].height;var imgWidth = img.width;var imgHeight = img.height;var imgYOffset = 20;// 计算宽高比和缩放比例var scaledWidth = 0;var scaledHeight = 0;if (imgWidth > imgHeight) {scaledWidth = 190;scaledHeight = Math.floor(scaledWidth * (imgHeight/imgWidth));} else {scaledHeight = 210;scaledWidth = Math.floor(scaledHeight * (imgWidth/imgHeight));}// 清除 Canvas// ctx.clearRect(0, 0, canvasWidth, canvasHeight);ctx.fillStyle = '#081c31';ctx.strokeStyle = '#081c31';ctx.fillRect(0, 0, canvasWidth, canvasHeight);var x = Math.floor((210 - scaledWidth) / 2);var y = Math.floor((210 - scaledHeight) / 2);ctx.drawImage(img, x, y+imgYOffset, scaledWidth, scaledHeight);// 读取图像const src = cv.imread(canvas[0]);// 创建一个目标矩阵用于灰度图像var gray = new cv.Mat();cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);//它创建了一个矩形区域(ROI,Region of Interest)并从灰度图像中提取该区域let rect = new cv.Rect(x,y+imgYOffset,scaledWidth,scaledHeight);gray = gray.roi(rect);// 创建 MatVector 并添加灰度图像const matVector = new cv.MatVector();matVector.push_back(gray);// 计算直方图const histSize = [256]; // 直方图的大小const ranges = [0, 256]; // 像素值范围const hist = new cv.Mat(); // 直方图结果const channels = [0]; // 通道索引const mask = new cv.Mat(); // 掩码cv.calcHist(matVector, channels, mask, hist, histSize, ranges);// 找到直方图的波峰const histData = hist.data32F; // 获取直方图数据let maxVal = 0;let maxIdx = 0;for (let i = 0; i < histSize[0]; i++) {if (histData[i] > maxVal) {maxVal = histData[i];maxIdx = i;}}// 波峰 ±150 的范围const lowerBound = maxIdx - 25;const upperBound = maxIdx + 25;console.log("222")console.log(maxIdx);// 创建一个红色的图像const redImage = new cv.Mat(src.rows, src.cols, src.type(), [255, 0, 0, 255]);for (let i = y+imgYOffset; i < y+imgYOffset+scaledHeight; i++) {for (let j = x; j < x+scaledWidth; j++) {const pixel = src.ucharPtr(i, j)[1];if (pixel < lowerBound || pixel > upperBound) {// 将不在波峰 ±150 范围内的像素变为红色src.ucharPtr(i, j)[0] = 255; // Rsrc.ucharPtr(i, j)[1] = 0;   // Gsrc.ucharPtr(i, j)[2] = 0;   // B}}}// 显示结果cv.imshow(canvas[0], src);// 释放内存src.delete();gray.delete();matVector.delete();hist.delete();mask.delete();redImage.delete();// result.delete();// 绘制刻度线const scaleLineY = y+20; // 刻度线距离顶部的距离(原为20,增加5个单位)const scaleLineLength = scaledWidth; // 刻度线的长度const scaleLineX =x; // 刻度线的起始X坐标ctx.strokeStyle = '#fbf321'; // 刻度线颜色ctx.lineWidth = 2; // 刻度线宽度ctx.beginPath();ctx.moveTo(scaleLineX, scaleLineY);ctx.lineTo(scaleLineX + scaleLineLength, scaleLineY);ctx.stroke();// 绘制刻度标记(可选)const numTicks = 10; // 刻度标记的数量const tickLength = 5; // 刻度标记的长度const middleTickLength = 10; // 中间刻度标记的长度const tickSpacing = scaleLineLength / numTicks; // 刻度标记之间的间距for (let i = 0; i <= numTicks; i++) {const tickX = scaleLineX + i * tickSpacing;const isMiddleTick = i === numTicks / 2; // 判断是否为中间刻度const currentTickLength = isMiddleTick ? middleTickLength : tickLength; // 如果是中间刻度,使用更长的长度ctx.beginPath();ctx.moveTo(tickX, scaleLineY);ctx.lineTo(tickX, scaleLineY - currentTickLength); // 刻度线向上绘制ctx.stroke();// 在最左面标注“0”if (i === 0) {ctx.fillStyle = '#ffffff'; // 文本颜色ctx.font = '12px Arial'; // 字体大小和样式ctx.textAlign = 'left'; // 文本左对齐ctx.textBaseline = 'bottom'; // 文本底部对齐ctx.fillText('0', tickX, scaleLineY - currentTickLength - 1); // 在刻度线上方标注“0”}}// 标注图像长度ctx.fillStyle = '#ffffff'; // 文本颜色ctx.font = '12px Arial'; // 字体大小和样式ctx.textAlign = 'right'; // 文本右对齐ctx.textBaseline = 'middle'; // 文本垂直居中对齐// 在刻度线最右面标注图像长度const labelX = scaleLineX + scaleLineLength + 20; // 文本的X坐标(刻度线最右端 + 10个单位)const labelY = scaleLineY - 11; // 文本的Y坐标(在刻度线上方,原为15,增加5个单位)if (this.flagf == 1) {ctx.fillText(`${(imgWidth * 0.098).toFixed(2)}mm`, labelX, labelY);} else {ctx.fillText(`${(imgWidth * 0.103).toFixed(2)}mm`, labelX, labelY);}// 右侧刻度线的位置和长度const scaleLineXRight = scaleLineX + scaledWidth; // 右侧刻度线的X坐标(图片右侧偏移20像素)const scaleLineYRight = y+20; // 右侧刻度线的Y坐标(从顶部开始)var scaleLineLengthRight = 0;if (imgHeight - imgWidth > 30) {scaleLineLengthRight = scaledHeight; // 右侧刻度线的长度(与图片高度相同)} else {scaleLineLengthRight = scaledHeight; // 右侧刻度线的长度(与图片高度相同)}// 绘制右侧刻度线ctx.strokeStyle = '#fbf321'; // 刻度线颜色ctx.lineWidth = 2; // 刻度线宽度ctx.beginPath();ctx.moveTo(scaleLineXRight, scaleLineYRight);ctx.lineTo(scaleLineXRight, scaleLineYRight + scaleLineLengthRight);ctx.stroke();// 绘制右侧刻度标记(可选)const numTicksRight = 10; // 刻度标记的数量const tickLengthRight = 5; // 刻度标记的长度const middleTickLengthRight = 10; // 中间刻度标记的长度const tickSpacingRight = scaleLineLengthRight / numTicksRight; // 刻度标记之间的间距for (let i = 0; i <= numTicksRight; i++) {const tickY = scaleLineYRight + i * tickSpacingRight;const isMiddleTick = i === numTicksRight / 2; // 判断是否为中间刻度const currentTickLength = isMiddleTick ? middleTickLengthRight : tickLengthRight; // 如果是中间刻度,使用更长的长度ctx.beginPath();ctx.moveTo(scaleLineXRight, tickY);ctx.lineTo(scaleLineXRight + currentTickLength, tickY); // 刻度线向右绘制ctx.stroke();// 在最上面的刻度位置显示 "0"if (i === 0) {ctx.fillStyle = '#ffffff'; // 文本颜色ctx.font = '12px Arial'; // 字体大小和样式ctx.textAlign = 'left'; // 文本左对齐ctx.textBaseline = 'middle'; // 文本垂直居中对齐ctx.fillText('0', scaleLineXRight + currentTickLength + 5, tickY); // 在刻度线右侧绘制 "0"}}// 标注图像高度ctx.fillStyle = '#ffffff'; // 文本颜色ctx.font = '12px Arial'; // 字体大小和样式ctx.textAlign = 'center'; // 文本居中对齐ctx.textBaseline = 'middle'; // 文本垂直居中对齐// 在右侧刻度线最下面标注图像高度const labelXRight = scaleLineXRight + 30; // 文本的X坐标(刻度线右侧偏移15像素)const labelYRight = scaleLineYRight + scaleLineLengthRight - 10; // 文本的Y坐标(在刻度线最下面)if (this.flagf == 1) {ctx.fillText(`${(imgHeight * 0.098).toFixed(2)}mm`, labelXRight, labelYRight); // 绘制文本} else {ctx.fillText(`${(imgHeight * 0.103).toFixed(2)}mm`, labelXRight, labelYRight); // 绘制文本}});},processImage2(img) {this.$nextTick(() => {console.log("ppsasasa")const canvas = this.$refs.myCanvas;const ctx = canvas[0].getContext('2d');var canvasWidth = canvas[0].width;var canvasHeight = canvas[0].height;var imgWidth = img.width;var imgHeight = img.height;var imgYOffset = 20;// 计算宽高比和缩放比例var scaledWidth = 0;var scaledHeight = 0;if (imgWidth > imgHeight) {scaledWidth = 190;scaledHeight = Math.floor(scaledWidth * (imgHeight/imgWidth));} else {scaledHeight = 210;scaledWidth = Math.floor(scaledHeight * (imgWidth/imgHeight));}// 清除 Canvasctx.clearRect(0, 0, canvasWidth, canvasHeight);ctx.fillStyle = '#081c31';ctx.strokeStyle = '#081c31';ctx.fillRect(0, 0, canvasWidth, canvasHeight);var x = Math.floor((210 - scaledWidth) / 2);var y = Math.floor((210 - scaledHeight) / 2);ctx.drawImage(img, x, y+imgYOffset, scaledWidth, scaledHeight);// 读取图像const src = cv.imread(canvas[0]);// // 创建一个目标矩阵用于灰度图像// const gray = new cv.Mat();// cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);// // 创建一个二值化图像,将白色区域分离出来// const binary = new cv.Mat();// cv.threshold(gray, binary, 170, 255, cv.THRESH_BINARY);// // // 将二值化图像作为掩码,将红色图像应用到白色区域// const result = new cv.Mat();// // 将原始图像中非白色区域保留// cv.bitwise_not(binary, binary);// cv.bitwise_and(src, src, result, binary);// // 显示结果// cv.imshow(canvas[0], result);// // 释放内存// src.delete();// gray.delete();// binary.delete();// result.delete();// 绘制刻度线const scaleLineY = y+20; // 刻度线距离顶部的距离(原为20,增加5个单位)const scaleLineLength = scaledWidth; // 刻度线的长度const scaleLineX =x; // 刻度线的起始X坐标ctx.strokeStyle = '#fbf321'; // 刻度线颜色ctx.lineWidth = 2; // 刻度线宽度ctx.beginPath();ctx.moveTo(scaleLineX, scaleLineY);ctx.lineTo(scaleLineX + scaleLineLength, scaleLineY);ctx.stroke();// 绘制刻度标记(可选)const numTicks = 10; // 刻度标记的数量const tickLength = 5; // 刻度标记的长度const middleTickLength = 10; // 中间刻度标记的长度const tickSpacing = scaleLineLength / numTicks; // 刻度标记之间的间距for (let i = 0; i <= numTicks; i++) {const tickX = scaleLineX + i * tickSpacing;const isMiddleTick = i === numTicks / 2; // 判断是否为中间刻度const currentTickLength = isMiddleTick ? middleTickLength : tickLength; // 如果是中间刻度,使用更长的长度ctx.beginPath();ctx.moveTo(tickX, scaleLineY);ctx.lineTo(tickX, scaleLineY - currentTickLength); // 刻度线向上绘制ctx.stroke();// 在最左面标注“0”if (i === 0) {ctx.fillStyle = '#ffffff'; // 文本颜色ctx.font = '12px Arial'; // 字体大小和样式ctx.textAlign = 'left'; // 文本左对齐ctx.textBaseline = 'bottom'; // 文本底部对齐ctx.fillText('0', tickX, scaleLineY - currentTickLength - 1); // 在刻度线上方标注“0”}}// 标注图像长度ctx.fillStyle = '#ffffff'; // 文本颜色ctx.font = '12px Arial'; // 字体大小和样式ctx.textAlign = 'right'; // 文本右对齐ctx.textBaseline = 'middle'; // 文本垂直居中对齐// 在刻度线最右面标注图像长度const labelX = scaleLineX + scaleLineLength + 20; // 文本的X坐标(刻度线最右端 + 10个单位)const labelY = scaleLineY - 11; // 文本的Y坐标(在刻度线上方,原为15,增加5个单位)if (this.flagf == 1) {ctx.fillText(`${(imgWidth * 0.098).toFixed(2)}mm`, labelX, labelY);} else {ctx.fillText(`${(imgWidth * 0.103).toFixed(2)}mm`, labelX, labelY);}// 右侧刻度线的位置和长度const scaleLineXRight = scaleLineX + scaledWidth; // 右侧刻度线的X坐标(图片右侧偏移20像素)const scaleLineYRight = y+20; // 右侧刻度线的Y坐标(从顶部开始)var scaleLineLengthRight = 0;if (imgHeight - imgWidth > 30) {scaleLineLengthRight = scaledHeight; // 右侧刻度线的长度(与图片高度相同)} else {scaleLineLengthRight = scaledHeight; // 右侧刻度线的长度(与图片高度相同)}// 绘制右侧刻度线ctx.strokeStyle = '#fbf321'; // 刻度线颜色ctx.lineWidth = 2; // 刻度线宽度ctx.beginPath();ctx.moveTo(scaleLineXRight, scaleLineYRight);ctx.lineTo(scaleLineXRight, scaleLineYRight + scaleLineLengthRight);ctx.stroke();// 绘制右侧刻度标记(可选)const numTicksRight = 10; // 刻度标记的数量const tickLengthRight = 5; // 刻度标记的长度const middleTickLengthRight = 10; // 中间刻度标记的长度const tickSpacingRight = scaleLineLengthRight / numTicksRight; // 刻度标记之间的间距for (let i = 0; i <= numTicksRight; i++) {const tickY = scaleLineYRight + i * tickSpacingRight;const isMiddleTick = i === numTicksRight / 2; // 判断是否为中间刻度const currentTickLength = isMiddleTick ? middleTickLengthRight : tickLengthRight; // 如果是中间刻度,使用更长的长度ctx.beginPath();ctx.moveTo(scaleLineXRight, tickY);ctx.lineTo(scaleLineXRight + currentTickLength, tickY); // 刻度线向右绘制ctx.stroke();// 在最上面的刻度位置显示 "0"if (i === 0) {ctx.fillStyle = '#ffffff'; // 文本颜色ctx.font = '12px Arial'; // 字体大小和样式ctx.textAlign = 'left'; // 文本左对齐ctx.textBaseline = 'middle'; // 文本垂直居中对齐ctx.fillText('0', scaleLineXRight + currentTickLength + 5, tickY); // 在刻度线右侧绘制 "0"}}// 标注图像高度ctx.fillStyle = '#ffffff'; // 文本颜色ctx.font = '12px Arial'; // 字体大小和样式ctx.textAlign = 'center'; // 文本居中对齐ctx.textBaseline = 'middle'; // 文本垂直居中对齐// 在右侧刻度线最下面标注图像高度const labelXRight = scaleLineXRight + 30; // 文本的X坐标(刻度线右侧偏移15像素)const labelYRight = scaleLineYRight + scaleLineLengthRight - 10; // 文本的Y坐标(在刻度线最下面)if (this.flagf == 1) {ctx.fillText(`${(imgHeight * 0.098).toFixed(2)}mm`, labelXRight, labelYRight); // 绘制文本} else {ctx.fillText(`${(imgHeight * 0.103).toFixed(2)}mm`, labelXRight, labelYRight); // 绘制文本}});},
http://www.xdnf.cn/news/401635.html

相关文章:

  • java每日精进 5.11【WebSocket】
  • Java后端文件类型检测(防伪造)
  • zuoyyyeee
  • 数据可视化:用一张图讲好一个故事
  • 安装Python和配置开发环境
  • 《 C++ 点滴漫谈: 三十七 》左值?右值?完美转发?C++ 引用的真相超乎你想象!
  • 创建三个网络,分别使用RIP、OSPF、静态,并每个网络10个电脑。使用DHCP分配IP
  • 第五十六篇 Java面向对象编程深度解析:构建高内聚低耦合的系统架构
  • Spring Boot中Redis序列化配置详解
  • 【美国将取消对能源之星支持 严重影响AI服务器】
  • 使用vite重构vue-cli的vue3项目
  • 基于粒子群算法的配电网重构
  • Kotlin与Qt跨平台框架深度解析:业务逻辑共享与多语言集成
  • MySQL-逻辑架构
  • python二手书交易管理系统
  • 如何调整yarn.nodemanager.vmem-pmem-ratio参数?
  • 什么是IP专线?企业数字化转型的关键网络基础设施
  • 阿里云人工智能大模型通义千问Qwen3开发部署
  • ASP.NET Core Identity框架使用指南
  • suricata增加单元测试编译失败
  • cursor 出现 unauthorized request
  • Maven私服搭建与登录全攻略
  • [redis进阶六]详解redis作为缓存分布式锁
  • 贝叶斯算法
  • 【pypi镜像源】使用devpi实现python镜像源代理(缓存加速,私有仓库,版本控制)
  • C#调用YOLOV8实现定位
  • PyCharm 快捷键指南
  • Android11.0 framework第三方无源码APP读写断电后数据丢失问题解决
  • 嵌入式系统:从基础到应用的全面解析
  • 【程序员AI入门:开发】12.AI Agent 革命:从聊天机器人到智能工作流的跃迁