使用opencvjs提取图片中的红色印章

news/2025/3/15 11:07:40/文章来源:https://www.cnblogs.com/xxss0903/p/18504621

首先看下效果:

首先对于纯红色的印章提取,也就是通过提取红色 的像素然后得到印章的结果,然后通过在红色的图像中寻找圆圈检测来进行圈定印章的位置
源码位置:https://github.com/xxss0903/extractstamp

  • 第一步是提取红色内容
function extractStampWithColorToOpencvMat(img,setColor = "#ff0000"
) {if (cvReady) {// 获取图片的宽高const imgWidth = img.width;const imgHeight = img.height;console.log("图片宽度:", imgWidth, "图片高度:", imgHeight);let src = cv.imread(img);let dst = new cv.Mat();let mask = new cv.Mat();// 转换为HSV颜色空间cv.cvtColor(src, dst, cv.COLOR_RGBA2RGB);cv.cvtColor(dst, dst, cv.COLOR_RGB2HSV);// 定义红色的HSV范围// 低值范围 (0-10)let lowRedA = new cv.Mat(dst.rows, dst.cols, dst.type(), [0, 50, 50, 0]);let highRedA = new cv.Mat(dst.rows, dst.cols, dst.type(), [10, 255, 255, 255]);// 高值范围 (170-180)let lowRedB = new cv.Mat(dst.rows, dst.cols, dst.type(), [170, 50, 50, 0]);let highRedB = new cv.Mat(dst.rows, dst.cols, dst.type(), [180, 255, 255, 255]);// 创建掩码let maskA = new cv.Mat();let maskB = new cv.Mat();cv.inRange(dst, lowRedA, highRedA, maskA);cv.inRange(dst, lowRedB, highRedB, maskB);// 合并掩码cv.add(maskA, maskB, mask);// 将十六进制颜色值转换为RGBAconst dstColor = hexToRgba(setColor);console.log("dstColor:", dstColor);// 创建带有 alpha 通道的目标图像let result = new cv.Mat(src.rows, src.cols, cv.CV_8UC4, [0, 0, 0, 0]);// 创建指定颜色的图像(带有 alpha 通道)let colorMat = new cv.Mat(src.rows, src.cols, cv.CV_8UC4, [...dstColor.slice(0, 3),255,]);// 使用掩码将提取的区域设置为指定颜色,非提取区域保持透明colorMat.copyTo(result, mask);// 释放内存src.delete();dst.delete();mask.delete();maskA.delete();maskB.delete();lowRedA.delete();highRedA.delete();lowRedB.delete();highRedB.delete();colorMat.delete();return result;} else {console.error("OpenCV.js 未加载");return img;}
}
  • 第二步,提取圆形印章,然后裁剪下来
function extractCirclesWithCvMat(cvMat) {let dst = new cv.Mat();// 转换为灰度图cv.cvtColor(cvMat, dst, cv.COLOR_RGBA2GRAY);// 应用高斯模糊以减少噪声cv.GaussianBlur(dst, dst, new cv.Size(5, 5), 2, 2);let croppedStamps = [];// 检测圆形let circles = detectCircles(dst);console.log("circles:", circles);circles.forEach((circle) => {console.log("draw circle:", circle);croppedStamps.push(cropAndDownloadCircle(cvMat, circle));});// 释放内存dst.delete();return croppedStamps;
}
  • 第三步,裁剪圆形印章
function cropAndDownloadCircle(cvMat, circle) {// 定义缩放因子,使裁剪范围比圆形大一些const scaleFactor = 1.2;// 计算新的半径和尺寸let newRadius = circle.radius * scaleFactor;let size = Math.round(newRadius * 2);// 创建一个新的Mat来存储裁剪后的图像let croppedMat = new cv.Mat();let rect = new cv.Rect(Math.round(circle.x - newRadius),Math.round(circle.y - newRadius),size,size);// 确保裁剪区域在图像范围内rect.x = Math.max(0, Math.min(rect.x, cvMat.cols - rect.width));rect.y = Math.max(0, Math.min(rect.y, cvMat.rows - rect.height));rect.width = Math.min(rect.width, cvMat.cols - rect.x);rect.height = Math.min(rect.height, cvMat.rows - rect.y);// 裁剪图像croppedMat = cvMat.roi(rect);// 创建圆形掩码let mask = new cv.Mat.zeros(size, size, cv.CV_8UC1);let center = new cv.Point(size / 2, size / 2);cv.circle(mask, center, Math.round(newRadius), new cv.Scalar(255, 255, 255), -1);// 应用掩码let result = new cv.Mat();cv.bitwise_and(croppedMat, croppedMat, result, mask);// 将结果转换为PNG数据URLlet imgData = new ImageData(new Uint8ClampedArray(result.data), result.cols, result.rows);let canvas = document.createElement('canvas');canvas.width = result.cols;canvas.height = result.rows;let ctx = canvas.getContext('2d');ctx.putImageData(imgData, 0, 0);let dataURL = canvas.toDataURL("image/png");// 释放内存croppedMat.delete();mask.delete();result.delete();return dataURL;
}

注意需要引入opencv.js,可以在index.html中引入
<script src="https://docs.opencv.org/4.x/opencv.js" type="text/javascript"></script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/822546.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ELE-Electronics

Electronics是一本关于电子科学及其应用的国际同行评审开放获取期刊,同时也是一本跨学科多主题征稿期刊。@目录一、征稿简介二、重要信息三、服务简述四、投稿须知 一、征稿简介二、重要信息期刊官网:https://ais.cn/u/3eEJNv三、服务简述 CT/MRI图像中基于学习的韧带分割; 计…

题目集1~3总结与分析

一.前言 知识点考查和难度: 题目集一第一题 设计风扇Fan类考查了Java类的组成部分和具体的组成内容。 题目集一第二题 巩固了类和对象的使用,和其中的构造方法。 题目集一第三题 在第二题考查基础上添加了具体的方法。 题目集一第四题 进一步学习类的使用,做了简单的关联类…

idea 将文件夹改成source

首先可以 使用idea 右键选择 要更改的文件 make Directory as 选择 sources Root如果文件 不能选择, 可以 IDEA 直接点击 FILE 菜单 ,然后选择 Project Structure 然后 在 Modules 中,可以将文件夹 更改类型。

2024 CSP-J

2024 CSP-J P11227 扑克牌(模拟,STL) 题意 给定 \(n\) 张扑克牌,问若要凑齐所有花色点数,还需要几种牌。 数据规模与约定 对于 \(100\%\) 的数据,\(1 \le n\le 52\)。 题解 发现每种扑克牌是一个花色和点数的二元组。开一个二维数组当桶即可。 但是考虑到实现起来的方便性…

04 二进制

二进制位数,每个位都是右侧位数的两倍; 八位机,一次性处理八位数的二进制数10101010,八位数表示从0到255,比如八位绘画板一共255种颜色可以使用,一位数0、1为bit, 八位数构成一个基本数串作为为一个字节,基本数串byte,有些用字节作为储存单位;内存已经到GB,TB上万亿字…

Dynamics 365 查找类型的字段,选择界面要去掉新增按钮,但是不能去掉新增权限

Dynamics 365 查找类型的字段,选择界面要去掉新增按钮,但是不能去掉新增权限办法: 1、将对应的窗体添加到解决方案中,导出解决方案,解决方案里面可以隐藏。然后把字段的我记得是某个属性改为false就可以隐藏了 2、<IsInlineNewEnabled>false</IsInlineNewEnabled…

南昌航空大学-软件学院-22207107-胡优乐-JAVA第一次Blog作业

南昌航空大学-软件学院-22207107-胡优乐-JAVA第一次Blog作业 前言距离开学第一次接触java已然过去了将近两个月时间,在这段时间里我们总共进行了三次大作业联系,基于这三次大作业的体量及设计的知识点,难度分布,我做了以下的总结:1.第一次大作业总共有五题,分别是:1.设计…

IDEA如何将一个分支的代码合并到另一个分支(当前分支)

前言 我们在使用IDEA开发Java应用时,经常是和git一起使用的。我们对于git常用的操作包括提交,推送,拉取代码等。还有一个重要的功能是合并代码。 那么,我们应该如何合并代码呢? 如何合并代码 首先,我们选择当前的代码分支,点击一下。然后,我们点击下需要合并过来的分支…

SpringBoot编写WebApi~(1)idea创建项目并打包

1.idea创建springboot项目,参考 2、idea将springboot打包成jar,参考,对于新版idea默认使用gradle构建,则使用下面步骤build.gradle文件添加以下几行:// 打包配置 bootJar {archiveBaseName.set(xxx-project)archiveVersion.set(0.0.1)archiveFileName.set(xxx-project.jar…

基于Java+SpringBoot+Mysql实现的古诗词平台功能设计与实现二

三、系统设计这是一款商用的古诗词网站平台,学生可以也可以用作毕设,如果需要自己搭建一个小说或者古诗词平台这个就可以满足、该系统可以直接上线部署运行,如果有需要这样的系统可以联系一下我,或者二次开发 或其他需求都可以来联系我。 技术点 语言:Java 数据库:Mysql P…

题目集1~3的总结性Blog

一、前言相关知识点:1、第一次题目集主要是对java的类的设计以及相关的方法的使用,包括数组的使用方法,类和对象的使用等进行考察。2、第二次题目集则是对第一次题目集的一次强化以及补充,要求掌握排序以及查找相关方法的使用,以及对于类与对象的概念进行了强调。3、第三次…

java一阶段作业总结

前言第一次题目集主要学习了类和对象的基本使用,主要训练了对构造方法,私有公共属性,对象的封装的能力,建立起了基本的类的概念,题量正常,最后一题的设计建议十分有用!!!(我自己刚开始建会乱七八糟,但是有了这个框架建议后面每次迭代改进都可以照葫芦画瓢)第二次题…