node.js opencv 图片缩放旋转

Node.js OpenCv图片缩放旋转


前言

opencv 是一个高效的视觉处理库, 可以用它来进行人脸识别等操作. 我在实践中发现用它来进行基本的图片操作速度也是远大于canvas相关的api. 速度甚至比很多 native module要快. 所以下面我就演示下如何使用 opencv 来缩放和旋转图片

安装OpenCv

安装方法参考下官方链接 这里不在赘述

在package.json文件中引入opencv

添加 “opencv”: “^7.0.0” 即可, 如果你出现了编译错误, 可以尝试替换为下面的代码. 我这里使用的 Node.js 版本为 14.0.0

  "dependencies": {
    "opencv": "peterbraden/node-opencv"
  }

运行例子

可以运行 opencv 项目中自带 example, node_modules/opencv/examples 如果没有错误提示, 表示安装无误

旋转图片

const cv = require('opencv');
cv.readImage("./examples/files/mona.png", function(err, im){
  if(err) {
    console.log(err);
    return;
  }

  // 参考文档你可以得知旋转矩阵怎么构建: https://docs.opencv.org/3.4/dd/d52/tutorial_js_geometric_transformations.html
  let θ = 30 / 180 * Math.PI;
  let cos = Math.cos(θ), sin = Math.sin(θ);
  
  let floats32 = new Float32Array([cos,-sin,0,sin,cos,0]);
  let m = new cv.Matrix(2, 3, cv.Constants.CV_32F);
  m.put(floats32);

  im.warpAffine(mat, im.width(), im.height());
  im.save('./rotate-30.png');
})

平移代码类似不在举例

组合多种操作

通过文档我们可以得知, 其实 warpAffine 接受的参数是矩阵对象, 也就是说我们可以把多次旋转 & 平移操作组合为一个 Mat, 一次性应用到 im 上.

先看这个连接来回顾一下矩阵乘法
opencv 文档上的平移 & 旋转变换使用 2x3 矩阵来完成. 但 2x3 矩阵不能同 2x3 矩阵直接相乘(行列不匹配) 根据矩阵乘法, 如果一个 3x3 矩阵的样式是:

[
	[1, 0, 0]
	[0, 1, 0]
	[0, 0, 1]
]

注意最后一行是 0,0,1 那么它无论同什么矩阵相乘得到的矩阵的最后一行都是 0,0,1 也就是说 3x3 矩阵最后一行是不变的. 所以叠加多次矩阵操作的思路就是, 多个 3x3 矩阵相乘, 最后截取为 2x3 矩阵.

抽象自己的矩阵操作

这里引入一个数学库 mathjs, 当然你也可以使用其他的数学库. 基于它封装出我们的矩阵类型

const cv = require('opencv');
const mathjs = require('mathjs');

// --------------------------
// Transform
// --------------------------
/**
 * 叠加多次操作
 * @constructor
 */
function Transform() {
  this._mat = mathjs.matrix([
    [1, 0, 0],
    [0, 1, 0],
    [0, 0, 1],
  ]);
}

/**
 * 移动到某位置
 * @param {number} x
 * @param {number} y
 * @param {number} [scale]
 */
Transform.prototype.transTo = function (x, y, scale = 1) {
  this._mat = mathjs.multiply(this._mat, mathjs.matrix([
    [scale, 0, x],
    [0, scale, y],
    [0, 0, 1],
  ]));
};
/**
 * 旋转
 * @param {number} x
 * @param {number} y
 * @param {number} degree  旋转角度(-90~90)
 * @param {number} [scale] 缩放
 */
Transform.prototype.rotateWith = function (x, y, degree, scale = 1) {
  let arc = (degree / 180) * Math.PI;
  let alpha = scale * Math.cos(arc);
  let beta = scale * Math.sin(arc);
  this._mat = mathjs.multiply(this._mat, mathjs.matrix([
    [alpha, beta, (1 - alpha) * x - beta * y],
    [-beta, alpha, beta * x + (1 - alpha) * y],
    [0, 0, 1],
  ]));
};
/**
 * 获得应用到 image 上的 matrix
 */
Transform.prototype.getMat = function () {
  let data = mathjs.flatten(this._mat).toArray().slice(0, -3);
  let floats32 = new Float32Array(data);
  let m = new cv.Matrix(2, 3, cv.Constants.CV_32F);
  m.put(floats32);
  return m;
};

module.exports = Transform;

验证

const Transform = require('./transform.js');

cv.readImage("./examples/files/mona.png", function(err, im){
  if(err) {
    console.log(err);
    return;
  }

  let trans = new Transform();
  trans.transTo(100, 50, 1);
  trans.rotateWith(100, 100, 30, 1);
  let mat = trans.getMat();

  im.warpAffine(mat, im.width(), im.height());
  im.save('./rotate-30.png');
})

代码虽然不多, 但node.js opencv的文档确实是少. 这些操作是我直接阅读 opencv c++ binding 代码结合 python 文档写出来的, 是在是呕心沥血了. 短短200行不到费了一天时间. 所以必须要广告一波

广告一波

如果你恰好要采购阿里云产品来我的推广链接看看吧:折扣码

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wlpsjgs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值