前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >前端图像处理之滤镜

前端图像处理之滤镜

作者头像
WecTeam
发布2020-02-17 15:40:54
1K0
发布2020-02-17 15:40:54
举报
文章被收录于专栏:WecTeamWecTeam

前言

滤镜主要是用来实现图像的各种特殊效果,比如灰色、颜色反转、黑白、马赛克、锐化等,我们在 Photoshop 中处理图片时经常能看到,这些看似很复杂的功能前端同学通过 Canvas 也能很容易实现。本文先通过几个简单的例子,解释如何实现简单的滤镜效果;之后再介绍卷积的基础知识,通过卷积运算来实现比较复杂的滤镜效果。

一、基础

1、图像处理流程中所用到的 Canvas API 主要有:

  • 清空给定矩形内的指定像素:clearRect(x, y, width, height)
  • 向画布上面绘制图片:drawImage(img, x, y, width, height)
  • 返回画布指定矩形的像素数据:getImageData(x, y, width, height)
  • 将图像数据放回画布上:putImageData(imgData, x, y)

2、处理过程

代码如下:

代码语言:javascript
复制
<canvas id="my_canvas"></canvas>
代码语言:javascript
复制
// 滤镜函数function filter (imageData, ctx) {
    // todo... 处理 imageDatareturn imageData;
}

// 加载图片let img = new Image();
img.src = "img.jpg";
img.onload = function () {
    // canvaslet myCanvas = document.querySelector("#my_canvas");
    myCanvas.width = 400;
    myCanvas.height = 300;
    let myContext = myCanvas.getContext("2d");

    // 将图片绘制到画布中
    myContext.drawImage(img, 0, 0, myCanvas.width, myCanvas.height);
    // 获取画布的像素数据let imageData = myContext.getImageData(0, 0, myCanvas.width, myCanvas.height);
    // 处理像素数据
    imageData = filter(imageData, myContext);
    // 将处理过的像素数据放回画布
    myContext.putImageData(imageData, 0, 0);
}

处理过程很简单,可是如何处理像素数据呢?

3、认识像素数据

代码语言:javascript
复制
// 从 x=0,y=0 开始,取宽=2,高=2 的像素数据let imageData = ctx.getImageData(0, 0, 2, 2)
console.log(imageData);

getImageData 获取图片像素数据,方法返回 ImageData 对象,是拷贝了画布指定矩形的像素数据,如下图

imageData.data 中有四个(宽 x 高=2x2=4)像素的数据,每个像素数据,都存在着四方面的信息,即 RGBA 值:R - 红色 (0-255; 0 是黑色,255 是纯红色) G - 绿色 (0-255; 0 是黑色,255 是纯绿色) B - 蓝色 (0-255; 0 是黑色的,255 是纯蓝色) A – 透明度 (0-255; 0 是透明的,255 是完全可见不透明的)

二、实现滤镜

既然我们知道了像素数据的含义,就可以在 filter 函数中对像素数据 imageData 进行相应的数学运算即可,现在我们对这三只小狗下手

1、单色滤镜(红色)

顾名思义,就是只保留红色值不变,把绿色和蓝色去除掉(值设为 0)

代码语言:javascript
复制
// 滤镜函数 - 红色滤镜function filter (imageData, ctx) {
    let imageData_length = imageData.data.length / 4; // 4 个为一个像素for (let i = 0; i < imageData_length; i++) {
        // imageData.data[i * 4 + 0] = 0;  // 红色值不变
        imageData.data[i * 4 + 1] = 0; // 绿色值设置为 0
        imageData.data[i * 4 + 2] = 0; // 蓝色值设置为 0
    }
    return imageData;
}

效果如下:

2、灰色滤镜

黑白照片效果,将颜色的 RGB 设置为相同的值即可使得图片为灰色,我们可以取三个色值的平均值。

代码语言:javascript
复制
// 滤镜函数 - 灰色滤镜function filter (imageData, ctx) {
    let imageData_length = imageData.data.length / 4; // 4 个为一个像素for (let i = 0; i < imageData_length; i++) {
        let newColor = (imageData.data[i * 4] + imageData.data[i * 4 + 1] + imageData.data[i * 4 + 2]) / 3;
        imageData.data[i * 4 + 0] = newColor;
        imageData.data[i * 4 + 1] = newColor;
        imageData.data[i * 4 + 2] = newColor;
    }
    return imageData;
}

效果如下:

3、反向滤镜

就是 RGB 三种颜色分别取 255 的差值

代码语言:javascript
复制
// 滤镜函数 - 反向滤镜function filter (imageData, ctx) {
    let imageData_length = imageData.data.length / 4; // 4 个为一个像素for (let i = 0; i < imageData_length; i++) {
        imageData.data[i * 4 + 0] = 255 - imageData.data[i * 4];
        imageData.data[i * 4 + 1] =  255 - imageData.data[i * 4 + 1];
        imageData.data[i * 4 + 2] =  255 - imageData.data[i * 4 + 2];
    }
    return imageData;
}

效果如下:

以上,通过控制每个像素 4 个数据的值,即可达到简单滤镜的效果。但是复杂的滤镜比如边缘检测,就需要用到卷积运算来实现。

三、卷积

卷积是一个常用的图像处理技术。在图像处理中,卷积操作是使用一个卷积核(kernel)对图像中的每一个像素进行一些列操作,可以改变像素强度,使用卷积技术,你可以获取一些流行的图像效果,比如边缘检测、锐化、模糊、浮雕等。

上图就是通过卷积运算后,输出的边缘检测图像效果,如果通过上面简单滤镜算法,很难想象我们能找到物体的边缘!现在来看一下怎么实现。

1、卷积运算过程

卷积运算是使用一个卷积核对输入图像中的每个像素进行一系列四则运算。卷积核(算子)是用来做图像处理时的矩阵,通常为 3x3 矩阵。使用卷积进行计算时,需要将卷积核的中心放置在要计算的像素上,一次计算核中每个元素和其覆盖的图像像素值的乘积并求和,得到的结构就是该位置的新像素值。

计算步骤如下:1、我们使用 3×3 的卷积核,将其覆盖在输入图像,对应的数字相乘,最后全部相加,即可得到第一个输出数据;2、把 3×3 的卷积核右移一格;3、重复 1 的计算过程,得到第二个数据;4、重复以上过程。

按照我们上面讲的图片卷积,如果原始图片尺寸为 6 x 6,卷积核尺寸为 3 x 3,则卷积后的图片尺寸为(6-3+1) x (6-3+1) = 4 x 4,卷积运算后,输出图片尺寸缩小了,这显然不是我们想要的结果!为了解决这个问题,可以使用 padding 方法,即把原始图片尺寸进行扩展,扩展区域补零,扩展尺寸为卷积核的半径(3x3 卷积核半径为 1,5x5 卷积核半径为 2)。

一个尺寸 6 x 6 的数据矩阵,经过 padding 后,尺寸变为 8 * 8,卷积运算后输出尺寸为 6 x 6,保证了图片尺寸不变化。

2、卷积核特性

  • 大小应该是奇数,这样它才有一个中心,例如 3x3,5x5 或者 7x7。
  • 卷积核上的每一位乘数被称为权值,它们决定了这个像素的分量有多重。
  • 它们的总和加起来如果等于 1,计算结果不会改变图像的灰度强度。
  • 如果大于 1,会增加灰度强度,计算结果使得图像变亮。
  • 如果小于 1,会减少灰度强度,计算结果使得图像变暗。
  • 如果和为 0,计算结果图像不会变黑,但也会非常暗。

3、边缘检测

常用于检测物体边缘的卷积核是一个中间是 8,周围是-1 的 3x3 数据矩阵。

我们能感受到物体的边缘,是因为边缘有明显的色差。假设输入图像的部分色值为 10,部分色值为 50,那么 10 和 50 之间就存在色差,边缘就在这个地方。经过卷积计算之后,我们可以看到色值相同的部分都变成了 0 表现为黑色,只有边缘的色值计算结果大于 0(色值最小是 0,负数色值也是黑色),即色值为 120 的边缘就凸显出来了!代码如下:

代码语言:javascript
复制
// 卷积计算函数function convolutionMatrix(output, input, kernel) {
    let w = input.width, h = input.height;
    let iD = input.data, oD = output.data;
    for (let y = 1; y < h - 1; y += 1) {
        for (let x = 1; x < w - 1; x += 1) {
            for (let c = 0; c < 3; c += 1) {
                let i = (y * w + x) * 4 + c;
                oD[i] = kernel[0] * iD[i - w * 4 - 4] +
                        kernel[1] * iD[i - w * 4] +
                        kernel[2] * iD[i - w * 4 + 4] +
                        kernel[3] * iD[i - 4] +
                        kernel[4] * iD[i] +
                        kernel[5] * iD[i + 4] +
                        kernel[6] * iD[i + w * 4 - 4] +
                        kernel[7] * iD[i + w * 4] +
                        kernel[8] * iD[i + w * 4 + 4];
            }
            oD[(y * w + x) * 4 + 3] = 255;
        }
    }
    return output;
}
// 滤镜函数function filter (imageData, ctx) {
    let kernel = [-1, -1, -1,
                  -1, 8, -1,
                  -1, -1, -1]; // 边缘检测卷积核return convolutionMatrix(ctx.createImageData(imageData), imageData, kernel);
}

我们只要使用不同的卷积核就能得到不同的图像处理效果,比如使用下面这个卷积核,就能得到锐化效果

代码语言:javascript
复制
let kernel = [-1, -1, -1,
              -1, 9, -1,
              -1, -1, -1]; // 锐化卷积核

锐化也是一种针对边缘处理(增强)的效果,前面有提到“卷积核的总和加起来如果等于 1,计算结果不会改变图像的灰度强度”。所以只要把边缘检测卷积核中间的 8 改为 9,就能实现边缘增强,且图片亮度不变的锐化效果!

四、总结

图像处理是一个很有意思的事情,大家还可以试试通过 navigator.mediaDevices 获取摄像头 video,然后通过 requestAnimationFrame 实时把当前 video 的图片数据通过滤镜处理后,再画到 canvas 中,这样我们就得到了滤镜处理过的视频(参考 Demo)!另外如果你看懂了本文的卷积部分,也许你就踏进了【神经网络与深度学习】的大门,因为卷积运算是神经网络与深度学习中最基本的组成部分,边缘检测只是一个入门样例,我们还可以用来做人脸识别等高级应用,想想都有一点小激动~

Demo

https://wqs.jd.com/demo/filter/index.html

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-01-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 WecTeam 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、基础
    • 1、图像处理流程中所用到的 Canvas API 主要有:
      • 2、处理过程
        • 3、认识像素数据
        • 二、实现滤镜
          • 1、单色滤镜(红色)
            • 2、灰色滤镜
              • 3、反向滤镜
              • 三、卷积
                • 1、卷积运算过程
                  • 2、卷积核特性
                    • 3、边缘检测
                    • 四、总结
                    • Demo
                    相关产品与服务
                    图像处理
                    图像处理基于腾讯云深度学习等人工智能技术,提供综合性的图像优化处理服务,包括图像质量评估、图像清晰度增强、图像智能裁剪等。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档