当前位置: 首页 > 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); // 绘制文本}});},

相关文章:

  • Scala和Spark的介绍
  • 深入浅出 iOS 对象模型:isa 指针 与 Swift Metadata
  • Spring Boot 使用Itext绘制并导出PDF
  • 创建三个网络,分别使用RIP、OSPF、静态,并每个网络10个电脑。使用DHCP分配IP
  • C++ 中介者模式详解
  • SAM论文学习
  • Windows系统安装VirtualBox-7及其以上的版本修改默认安装路径后提示
  • python标准库--heapq - 堆队列算法(优先队列)在算法比赛的应用
  • 【AI News | 20250512】每日AI进展
  • 使用Daemonset部署日志收集守护进程
  • 探索边缘计算:赋能物联网的未来
  • WEBSTORM前端 —— 第3章:移动 Web —— 第1节:平面转换、渐变
  • 快消品商超业务单据解决方案重塑KA商超、电商业务与SAP ERP协同效率
  • 动态人脸识别教学实训沙盘功能介绍
  • 扩展:React 项目执行 yarn eject 后的 package.json 变化详解及参数解析
  • Linux进程10-有名管道概述、创建、读写操作、两个管道进程间通信、读写规律(只读、只写、读写区别)、设置阻塞/非阻塞
  • Spark处理过程-转换算子和行动算子
  • Lodash isEqual 方法源码实现分析
  • Spring Cloud Sleuth 链路追踪
  • Java面试高阶篇:Spring Boot+Quarkus+Redis高并发架构设计与性能优化实战
  • 海北州委常委、常务副州长桑本履新青海省供销社理事会主任
  • 香港暂停进口美国北达科他州一地区禽肉及禽类产品
  • 加强战略矿产出口全链条管控工作部署会召开
  • 专访|家人眼中的周碧初:用色彩写诗,实践油画“民族化”
  • 金科股份重整方案通过,正式进入重整计划执行环节
  • 德国将不再公布对乌克兰军事支持的细节