OpenCV  4.10.0
开源计算机视觉
加载...
搜索...
未找到匹配项
图像上的基本操作

目标

  • 了解如何访问图像属性
  • 了解如何构建 Mat
  • 了解如何复制 Mat
  • 了解如何转换 Mat 的类型
  • 了解如何使用 MatVector
  • 了解如何访问像素值并修改它们
  • 了解如何设置感兴趣区域 (ROI)
  • 了解如何拆分和合并图像

访问图像属性

图像属性包括行数、列数和大小、深度、通道、图像数据类型。

let src = cv.imread("canvasInput");
console.log('image width: ' + src.cols + '\n' +
'image height: ' + src.rows + '\n' +
'image size: ' + src.size().width + '*' + src.size().height + '\n' +
'image depth: ' + src.depth() + '\n' +
'image channels ' + src.channels() + '\n' +
'image type: ' + src.type() + '\n');
注意
src.type() 在调试时非常重要,因为 OpenCV.js 代码中大量错误是由无效数据类型引起的。

如何构建 Mat

有 4 个基本构造函数

// 1. 默认构造函数
let mat = new cv.Mat();
// 2. 按大小和类型构造二维数组
let mat = new cv.Mat(size, type);
// 3. 按行、列和类型构造二维数组
let mat = new cv.Mat(rows, cols, type);
// 4. 按行、列、类型和初始化值构造二维数组
let mat = new cv.Mat(rows, cols, type, new cv.Scalar());

有 3 个静态函数

// 1. 创建一个全为零的 Mat
let mat = cv.Mat.zeros(rows, cols, type);
// 2. 创建一个全为一的 Mat
let mat = cv.Mat.ones(rows, cols, type);
// 3. 创建一个包含单位矩阵的 Mat
let mat = cv.Mat.eye(rows, cols, type);

有 2 个工厂函数

// 1. 使用 JS 数组构建一个矩阵
// 例如:let mat = cv.matFromArray(2, 2, cv.CV_8UC1, [1, 2, 3, 4]);
let mat = cv.matFromArray(rows, cols, type, array);
// 2. 使用 imgData 构建一个矩阵
let ctx = canvas.getContext("2d");
let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
let mat = cv.matFromImageData(imgData);
注意
不要忘记当你不再想使用时删除 cv.Mat

如何复制 Mat

有 2 种方式复制 Mat

// 1. 克隆
let dst = src.clone();
// 2. CopyTo(只有掩码中指出的条目被复制)
src.copyTo(dst, mask);

如何转换 Mat 的类型

我们使用函数:convertTo(m, rtype, alpha = 1, beta = 0)

参数
m输出矩阵;如果它在操作前没有适合的大小或类型,则重新分配它。
rtype所需的输出矩阵类型或者深度,因为通道数与输入的通道数相同;如果 rtype 为负,输出矩阵将与输入具有相同的类型。
alpha可选的缩放因子。
beta添加到缩放值中的可选增量。
src.convertTo(dst, rtype);

如何使用 MatVector

let mat = new cv.Mat();
// 初始化一个 MatVector
let matVec = new cv.MatVector();
// 将 Mat 放入 MatVector
matVec.push_back(mat);
// 从 MatVector 获取一个 Mat
let cnt = matVec.get(0);
mat.delete(); matVec.delete(); cnt.delete();
注意
当不再需要时,请记得删除 cv.Mat、cv.MatVector 和 cnt(从 MatVector 获取的 Mat)。

访问和修改像素值

首先,您应了解以下类型关系

数据属性C++ 类型JavaScript 类型化数组Mat 类型
dataucharUint8ArrayCV_8U
data8ScharInt8ArrayCV_8S
data16UushortUint16ArrayCV_16U
data16SshortInt16ArrayCV_16S
data32SintInt32ArrayCV_32S
data32FfloatFloat32ArrayCV_32F
data64FdoubleFloat64ArrayCV_64F

1. data

let row = 3, col = 4;
let src = cv.imread("canvasInput");
if (src.isContinuous()) {
let R = src.data[row * src.cols * src.channels() + col * src.channels()];
let G = src.data[row * src.cols * src.channels() + col * src.channels() + 1];
let B = src.data[row * src.cols * src.channels() + col * src.channels() + 2];
let A = src.data[row * src.cols * src.channels() + col * src.channels() + 3];
}
注意
数据操作仅对连续 Mat 有效。您应首先使用 isContinuous() 进行检查。

2. at

Mat 类型At 操作
CV_8UucharAt
CV_8ScharAt
CV_16UushortAt
CV_16SshortAt
CV_32SintAt
CV_32FfloatAt
CV_64FdoubleAt
let row = 3, col = 4;
let src = cv.imread("canvasInput");
let R = src.ucharAt(row, col * src.channels());
let G = src.ucharAt(row, col * src.channels() + 1);
let B = src.ucharAt(row, col * src.channels() + 2);
let A = src.ucharAt(row, col * src.channels() + 3);
注意
At 操作仅用于单通道访问并且不能修改值。

3. 指针

Mat 类型指针操作JavaScript 类型化数组
CV_8UucharPtrUint8Array
CV_8ScharPtrInt8Array
CV_16UushortPtrUint16Array
CV_16SshortPtrInt16Array
CV_32SintPtrInt32Array
CV_32FfloatPtrFloat32Array
CV_64FdoublePtrFloat64Array
let row = 3, col = 4;
let src = cv.imread("canvasInput");
设置像素 pixel = src.ucharPtr(row, col);
设置 R = pixel[0];
设置 G = pixel[1];
设置 B = pixel[2];
设置 A = pixel[3];

mat.ucharPtr(k) 获取 mat 的第 k 行。mat.ucharPtr(i, j) 获取 mat 的第 i 行 j 列。

图像感兴趣区域

有时,您必须处理图像的特定区域。对于图像中的眼睛检测,首先对图像执行人脸检测,获得人脸后,我们只选择人脸区域,在其中搜索眼睛,而不是搜索整个图像。它提高了准确性(因为眼睛始终位于人脸上)和性能(因为我们搜索的是一个小区域)

我们使用函数:roi (rect)

参数
rect感兴趣区域的矩形。

尝试一下

分离和合并图像通道

有时您需要对图像的 R、G、B 通道分别进行处理。然后您需要将 RGB 图像拆分为单个平面。或者在其他时候,您可能需要将这些各个通道合并到 RGB 图像中。

let src = cv.imread("canvasInput");
设置 rgbaPlanes = new cv.MatVector();
// 拆分 Mat
cv.split(src, rgbaPlanes);
// 获取 R 通道
设置 R = rgbaPlanes.get(0);
// 合并所有通道
cv.merge(rgbaPlanes, src);
src.delete(); rgbaPlanes.delete(); R.delete();
注意
当不再需要使用 cv.Mat、cv.MatVector 和 R(您从 MatVector 获得的 Mat)时,请不要忘记删除它们。

为图像创建边框(填充)

如果您想在图像周围创建一个边框,类似于相框,可以使用cv.copyMakeBorder()函数。但它还有更多关于卷积运算、零填充等的应用程序此函数采用以下参数

  • src - 输入图像
  • top, bottom, left, right - 相应方向中的边框宽度,以像素数计
  • borderType - 标志,用于定义要添加哪种类型的边框。它可以以下类型
  • value - 如果边框类型为 cv.BORDER_CONSTANT,则为边框颜色

试一试