上一节只讲了opencv.js如何读取和输出图像的,这一次继续扒官方的tutorials,造福中国人。
首先应当认清楚的是,opencv只是一个库,不是一种程序框架;而且上一节可以看出,在一整个html文件中,JavaScript也只不过在一个程序块中,那么这个程序块中的opencv含量显然相对就更少了。根据官方给的小例程,可以总结出opencv.js程序的构成大致是这样的:
看图还不直观,就直接上代码,步骤2以外的其他部分,除了有其他的需求,都可以看做是固定的模板!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello OpenCV.js</title>
<style>
.inputoutput{
float: left;
}
</style>
</head>
<body>
<h2>Program of OpenCV.js</h2>
<p id="status">OpenCV.js is loading...</p>
<div>
<div class="inputoutput">
<img id="imageSrc" alt="No Image" />
<div class="caption">imageSrc <input type="file" id="fileInput" name="file" /></div>
</div>
<div class="inputoutput">
<canvas id="canvasOutput" ></canvas>
<div class="caption">canvasOutput</div>
</div>
</div>
<script type="text/javascript">
var imgSrcElement=document.getElementById('imageSrc');
var imageInput=document.getElementById('fileInput');
imageInput.addEventListener('change',(e)=>{
imgSrcElement.src=URL.createObjectURL(e.target.files[0]);
})
// 因为是异步操作,所以需要onload等图像加载完毕后执行,也是回调
imgSrcElement.onload=function(){
// 读取获取矩阵(步骤1)
let src=cv.imread(imgSrcElement);
let dst = new cv.Mat(); //这个是输出矩阵
// 处理图像(步骤2)
//这里就是opencv.js的工作区
//其他地方和opencv.js的图像处理都莫得关系
//需要的处理代码按逻辑放在这一块里就可以
//如果创建了中间矩阵或矢量的话,也不要忘了在回调函数最后把堆的内存释放掉
// 输出获取矩阵(步骤3)
cv.imshow('canvasOutput',dst);
// 调用delete释放堆的内存
src.delete();
dst.delete();
}
var opencvLoad=function(){
document.getElementById('status').innerHTML='opencv is ready';//回调函数,用来显示opencv.js加载完成
}
</script>
<!-- 异步加载,不对程序进行阻塞 -->
<script async src="opencv.js" onload="opencvLoad()" type="text/javascript"></script>
</body>
</html>
opencv.js构造矩阵变量的方法:
// 1. 默认构造函数
let mat = new cv.Mat();
// 2. 2维数组型,参数为尺寸 类型
let mat = new cv.Mat(size, type);
// 3. 2维数组型,参数为行数 列数 类型
let mat = new cv.Mat(rows, cols, type);
// 4. 2维数组型,参数为行数 列数 类型 初始化颜色
let mat = new cv.Mat(rows, cols, type, new cv.Scalar());
// 1. 全为0的矩阵
let mat = cv.Mat.zeros(rows, cols, type);
// 2. 全为1的矩阵
let mat = cv.Mat.ones(rows, cols, type);
// 3. 创建单位矩阵
let mat = cv.Mat.eye(rows, cols, type);
opencv.js复制矩阵变量的方法:
// 1. 直接复制
let dst = src.clone();
// 2. 只复制掩码中指示的条目
src.copyTo(dst, mask);
opencv.js转换矩阵变量类型的方法:
src.convertTo(dst, rtype);//参数为目标矩阵 目标类型
绘制ROI是opencv的基本操作,这样能够有效减少图像处理的运算量。实现绘制ROI功能仅需要在程序模板中的步骤2内写入以下代码,就可以实现绘制矩形ROI:
let rect = new cv.Rect(100,100,200,200);//矩阵左上角坐标为(100,100),右下角坐标为(200,200)
dst = src.roi(rect);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello OpenCV.js</title>
<style>
.inputoutput{
float: left;
}
</style>
</head>
<body>
<h2>Program of OpenCV.js</h2>
<p id="status">OpenCV.js is loading...</p>
<div>
<div class="inputoutput">
<img id="imageSrc" alt="No Image" />
<div class="caption">imageSrc <input type="file" id="fileInput" name="file" /></div>
</div>
<div class="inputoutput">
<canvas id="canvasOutput" ></canvas>
<div class="caption">canvasOutput</div>
</div>
</div>
<script type="text/javascript">
var imgSrcElement=document.getElementById('imageSrc');
var imageInput=document.getElementById('fileInput');
imageInput.addEventListener('change',(e)=>{
imgSrcElement.src=URL.createObjectURL(e.target.files[0]);
})
// 因为是异步操作,所以需要onload等图像加载完毕后执行,也是回调
imgSrcElement.onload=function(){
// 读取获取矩阵(步骤1)
let src=cv.imread(imgSrcElement);
let dst = new cv.Mat();
// 处理图像(步骤2)
let rect = new cv.Rect(100,100,200,200);
dst = src.roi(rect);
// 输出获取矩阵(步骤3)
cv.imshow('canvasOutput',dst);
// 调用delete释放堆的内存
src.delete();
dst.delete();
}
var opencvLoad=function(){
document.getElementById('status').innerHTML='opencv is ready';//回调函数,用来显示opencv.js加载完成
}
</script>
<!-- 异步加载,不对程序进行阻塞 -->
<script async src="opencv.js" onload="opencvLoad()" type="text/javascript"></script>
</body>
</html>
轮廓填充只需要在步骤2中加入以下代码:
let s = new cv.Scalar(255,0,0,255);
cv.copyMakeBorder(src,dst,10,10,10,10,cv.BORDER_CONSTANT,s);//上,下,左,右方向填充
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello OpenCV.js</title>
<style>
.inputoutput{
float: left;
}
</style>
</head>
<body>
<h2>Program of OpenCV.js</h2>
<p id="status">OpenCV.js is loading...</p>
<div>
<div class="inputoutput">
<img id="imageSrc" alt="No Image" />
<div class="caption">imageSrc <input type="file" id="fileInput" name="file" /></div>
</div>
<div class="inputoutput">
<canvas id="canvasOutput" ></canvas>
<div class="caption">canvasOutput</div>
</div>
</div>
<script type="text/javascript">
var imgSrcElement=document.getElementById('imageSrc');
var imageInput=document.getElementById('fileInput');
imageInput.addEventListener('change',(e)=>{
imgSrcElement.src=URL.createObjectURL(e.target.files[0]);
})
// 因为是异步操作,所以需要onload等图像加载完毕后执行,也是回调
imgSrcElement.onload=function(){
// 读取获取矩阵(步骤1)
let src=cv.imread(imgSrcElement);
let dst = new cv.Mat();
// 处理图像(步骤2)
let s = new cv.Scalar(255,0,0,255);
cv.copyMakeBorder(src,dst,10,10,10,10,cv.BORDER_CONSTANT,s);//上,下,左,右方向填充
// 输出获取矩阵(步骤3)
cv.imshow('canvasOutput',dst);
// 调用delete释放堆的内存
src.delete();
dst.delete();
}
var opencvLoad=function(){
document.getElementById('status').innerHTML='opencv is ready';//回调函数,用来显示opencv.js加载完成
}
</script>
<!-- 异步加载,不对程序进行阻塞 -->
<script async src="opencv.js" onload="opencvLoad()" type="text/javascript"></script>
</body>
</html>
一般图像处理前通常会将图像矩阵由原先的RGB彩色转换为灰度模式。因为灰度模式计算的通道少,能够减少运算量。当然,需要涉及到颜色识别的程序另说。
灰度图转换只需要在步骤2中加入以下代码:
cv.cvtColor(src,dst,cv.COLOR_RGBA2GRAY,0);//最后一个参数为0的话通道数量由src自动生成
opencv.js支持三种形式的缩放变换,参数为:cv.INTER_AREA,cv.INTER_CUBIC, cv.INTER_LINEAR
以cubic形式举例,若要将原图像缩小到长200,宽200的尺寸,则需要在步骤2中写如下代码:
let dsize = new cv.Size(200,200);
cv.resize(src,dst,dsize,0,0,cv.INTER_CUBIC);