OpenCV的全称是Open Source Computer Vision Library,是一个跨平台的计算机视觉库。OpenCV是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研究领域中免费使用。OpenCV可用于开发实时的图像处理、计算机视觉以及模式识别程序。该程序库也可以使用英特尔公司的IPP进行加速处理。
OpenCV.js------连接OpenCV与JS开发者
随着HTML5的兴起,在web端使用图像处理相关技术显得尤为重要,OpenCV.js为Javascript开发者与OpenCV之间搭建了桥梁。起初是由Intel公司发起的一项研究,后在2017年并入到OpenCV项目中。
Emscripten,一款LLVM-to-JavaScript的编译器,将C++的底层函数编译成可以直接在浏览器端运行的asm.js或者WebAssembly。而OpenCV.js是通过该Emscripten将OpenCV的函数编译进asm.js或WebAssembly中,并提供JS APIs给web应用使用。
OpenCV.js的目标:
1. 实现OpenCV在web端的开发与使用
2. 帮助网络社区,开发人员和计算机视觉研究人员交互访问各种基于Web的OpenCV示例,帮助他们理解特定的视觉算法。
基本概念与操作
矩阵
OpenCV.js 引入了新的变量类型 ------ Mat类型,即矩阵类型,使用 let mat = new cv.Mat();
来创建新的矩阵类型,OpenCV.js 读取的图像均使用该类型存储。
图像的读取与写入
OpenCV.js 可以将 <img>
或者 <canvas>
的内容读取为矩阵类型用以变换,同时也可以将处理好的图像作为 <img>
或者 <canvas>
的内容,具体方法如下:
csharp
// 读取
let mat = cv.imread("inputCanvasId");
// 其中 inputCanvasId 为目标 DOM 元素的 id 属性
// 写入
cv.imshow(mat, "outputCanvasId");
// mat 为处理后图像矩阵变量
官方已经提供比较完整的说明文档,这里不详细介绍具体的 API 了,我们简单说一下用法。注意:所有的代码应该写在初始化函数onRuntimeInitialized中。cv 提供了imread(imageid | HTMLImageElement | HTMLCanvasElement) 的函数签名,这可以从指定的源读取图片内容,并返回一个cv.Mat类型的对象,这是一个基本的存储二维空间的数据结构------矩阵,这里用来存储图片的像素结构,后面很多操作都是基于Mat类型来操作的。输出图片也非常方便,直接调用cv.imshow(canvasid | HTMLCanvasElement, cv.Mat对象) 就可以把图像绘制在屏幕上。需要记住的是 WebAssembly 不会帮助你回收内存,所以记得 cv.Mat 对象用完后及时调用delete()方法释放内存。
图像数据类型
Mat 是 OpenCV 基础的图像数据结构,其数据类型对照表如下:
| Data Properties
| C++Type | JavaScript Typed Array | Mat Type | | --- | --- | --- | --- | | data | uchar | Uint8Array | CV_8U | | data8S | char | Int8Array | CV_8S | | data16U | ushort | Uint16Array | CV_16U | | data16S | short | Int16Array | CV_16S | | data32S | int | Int32Array | CV_32S | | data32F | float | Float32Array | CV_32F | | data64F | double | Float64Array | CV_64F |
灰度实现
xml
<!DOCTYPE html>
<html>
<head>
<title>OpenCV.js</title>
<style type="text/css">
.wrap-image {
display: flex;
flex-direction: row;
margin-top: 10px;
}
.wrap-image img,
.wrap-image canvas {
width: 300px;
margin-right: 10px;
}
</style>
</head>
<body>
<h3 id="status">Loading the Opencv ...</h3>
<input type="file" id="fileInput-gray"/>
<div class="wrap-image">
<img id="imageUpload-gray" alt="No Image" />
<canvas id="canvasOutput-gray"></canvas>
</div>
<script type="text/javascript">
//图片灰度处理效果:
let imgElement = document.getElementById('imageUpload-gray');
let inputElement = document.getElementById('fileInput-gray');
inputElement.onchange = function() {
imgElement.src = URL.createObjectURL(event.target.files[0]);
}
imgElement.onload =function() {
let src = cv.imread('imageUpload-gray');
let dst = new cv.Mat();
cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY, 0);
cv.imshow('canvasOutput-gray', dst);
src.delete(); dst.delete();
};
function onOpenCvReady() {
document.getElementById('status').remove();
}
</script>
<script async src="https://docs.opencv.org/4.5.3/opencv.js" onload="onOpenCvReady();" type="text/javascript"></script>
</body>
</html>
image.png
图像阈值处理
ini
//图片灰度处理效果:
let imgElement = document.getElementById('imageUpload');
let inputElement = document.getElementById('fileInput');
inputElement.onchange = function() {
imgElement.src = URL.createObjectURL(event.target.files[0]);
}
imgElement.onload =function() {
let src = cv.imread('imageUpload');
let dst = new cv.Mat();
// cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY, 0);
cv.threshold(src, dst, 177, 200, cv.THRESH_BINARY);
cv.imshow('canvasOutput', dst);
src.delete(); dst.delete();
};
function onOpenCvReady() {
document.getElementById('status').remove();
}
image.png
自适应阈值
ini
let imgElement = document.getElementById('imageUpload');
let inputElement = document.getElementById('fileInput');
inputElement.onchange = function() {
imgElement.src = URL.createObjectURL(event.target.files[0]);
}
imgElement.onload =function() {
let src = cv.imread('imageUpload');
let dst = new cv.Mat();
cv.cvtColor(src, src, cv.COLOR_RGBA2GRAY, 0);
// You can try more different parameters
cv.adaptiveThreshold(src, dst, 200, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 3, 2);
cv.imshow('canvasOutput', dst);
src.delete(); dst.delete();
};
function onOpenCvReady() {
document.getElementById('status').remove();
}
image.png
滤镜处理
ini
let imgElement = document.getElementById('imageUpload');
let inputElement = document.getElementById('fileInput');
inputElement.onchange = function() {
imgElement.src = URL.createObjectURL(event.target.files[0]);
}
imgElement.onload =function() {
let src = cv.imread('imageUpload');
let dst = new cv.Mat();
let M = cv.Mat.eye(3, 3, cv.CV_32FC1);
let anchor = new cv.Point(-1, -1);
// You can try more different parameters
cv.filter2D(src, dst, cv.CV_8U, M, anchor, 0, cv.BORDER_DEFAULT);
cv.imshow('canvasOutput', dst);
src.delete(); dst.delete();
};
function onOpenCvReady() {
document.getElementById('status').remove();
}
image.png
图像模糊
ini
let imgElement = document.getElementById('imageUpload');
let inputElement = document.getElementById('fileInput');
inputElement.onchange = function() {
imgElement.src = URL.createObjectURL(event.target.files[0]);
}
imgElement.onload =function() {
let src = cv.imread('imageUpload');
let dst = new cv.Mat();
let ksize = new cv.Size(3, 3);
// You can try more different parameters
cv.GaussianBlur(src, dst, ksize, 0, 0, cv.BORDER_DEFAULT);
cv.imshow('canvasOutput', dst);
src.delete(); dst.delete();
};
function onOpenCvReady() {
document.getElementById('status').remove();
}
image.png
图像直方图
ini
let imgElement = document.getElementById('imageUpload');
let inputElement = document.getElementById('fileInput');
inputElement.onchange = function() {
imgElement.src = URL.createObjectURL(event.target.files[0]);
}
imgElement.onload =function() {
let src = cv.imread('imageUpload');
// let dst = new cv.Mat();
// let src = cv.imread('canvasInput');
cv.cvtColor(src, src, cv.COLOR_RGBA2GRAY, 0);
let srcVec = new cv.MatVector();
srcVec.push_back(src);
let accumulate = false;
let channels = [0];
let histSize = [256];
let ranges = [0, 255];
let hist = new cv.Mat();
let mask = new cv.Mat();
let color = new cv.Scalar(255, 255, 255);
let scale = 2;
// You can try more different parameters
cv.calcHist(srcVec, channels, mask, hist, histSize, ranges, accumulate);
let result = cv.minMaxLoc(hist, mask);
let max = result.maxVal;
let dst = new cv.Mat.zeros(src.rows, histSize[0] * scale,
cv.CV_8UC3);
// draw histogram
for (let i = 0; i < histSize[0]; i++) {
let binVal = hist.data32F[i] * src.rows / max;
let point1 = new cv.Point(i * scale, src.rows - 1);
let point2 = new cv.Point((i + 1) * scale - 1, src.rows - binVal);
cv.rectangle(dst, point1, point2, color, cv.FILLED);
}
cv.imshow('canvasOutput', dst);
src.delete(); dst.delete(); srcVec.delete(); mask.delete(); hist.delete();
}
function onOpenCvReady() {
document.getElementById('status').remove();
}
image.png