如何用OpenCV.js制作乔丹动图素描效果教程?

2026-04-27 21:241阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计3326个文字,预计阅读时间需要14分钟。

如何用OpenCV.js制作乔丹动图素描效果教程?

目录 + 背景 + 技术 + OpenCV.js + 优势 + 地点 + 项目搭建 + 准备图片

1.引入OpenCV.js,查看OpenCV.js,引入状态

2.读取图片并显示

3.彩色图片转灰度图

4.对灰度图进行高斯模糊

5.图像二值化

目录
  • 背景
  • 技术
    • OpenCV.js 优点
    • OpenCV.js 地址
  • 项目搭建
    • 准备图片
    • 1. 引入 OpenCV.js
      • 查看 OpenCV.js 引入状态
    • 2. 读取图片并显示
      • 3. 彩色图片转成灰度图
        • 4. 对灰度图进行高斯模糊
          • 5. 图像二值化
            • 6.再次对二值化图像进行模糊
              • 7.再次进行二值化
                • 8.图像开运算
                  • 10.读取并处理视频中的图像
                  • 结语

                    背景

                    大家都知道,最近几年大热的AI(人工智能),并且使用AI做人脸识别和物品的分类,其实AI不光可以做这些基本操作,还可以用其来画素描,因为本人是乔丹的篮球粉丝,于是想用AI的技术来实现乔老爷子素描。

                    技术

                    因为本人是前端程序猿 爱好 AI,所以我会用前端和AI的方式来实现乔老爷子素描。正好OpenCV.js可以满足我们的需求。

                    OpenCV.js 优点

                    OpenCV.js 的出现使得 JavaScript 开发者可以高效便捷的使用 OpenCV 提供的图形处理算法,也就是说开发者仅凭借浏览器就能快速开发诸如图片风格美化、图像识别、OCR等功能的应用。

                    OpenCV.js 地址

                    文档:docs.opencv.org/4.x/index.h…

                    github:github.com/opencv/open…

                    闲话不多说,今天就让我们跟着乔老爷子一起用OpenCV实现素描效果吧!

                    项目搭建

                    准备图片

                    1. 引入 OpenCV.js

                    可以直接如下引入,也可以下载到本地,再引入:

                    <script src="docs.opencv.org/4.x/opencv.js"></script>

                    查看 OpenCV.js 引入状态

                    代码如下:

                    // html <p id="status">OpenCV.js is loading...</p>

                    // js let Module = { onRuntimeInitialized() { document.getElementById('status').innerHTML = 'OpenCV.js is ready.'; } }; Module.onRuntimeInitialized();

                    效果,当页面的 loading 变成 read ,说明已完成OpenCV.js加载。

                    2. 读取图片并显示

                    html 代码如下:

                    <div> <div class="inputoutput"> <img id="imageSrc" alt="No Image" width="100%" /> <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>

                    js 代码如下:

                    let imgElement = document.getElementById('imageSrc'); let inputElement = document.getElementById('fileInput'); inputElement.addEventListener('change', (e) => { imgElement.src = URL.createObjectURL(e.target.files[0]); }, false); imgElement.onload = function() { let img_origin = cv.imread(imgElement); cv.imshow('canvasOutput', img_origin); img_origin.delete(); };

                    效果如下图:

                    然后点击上传图片,上传图片后如下显示:

                    稍微解释一下上面的代码,首先我们可以本地上传一个图片,通过fileInput获取图片文件,并把图片传给imageSrc渲染,

                    然后我们利用cv.imread('demo.jpg')读取了这张图片,保存到img_origin这个变量里面。

                    接下来用cv.imshow('origin', img_origin)将这张照片通过一个canvas显示出来,并且这个窗口的名称叫做canvasOutput

                    3. 彩色图片转成灰度图

                    接下来我们要把彩色图片转换成灰度图:

                    function cvtColor(img_origin) { let img_gray = new cv.Mat(); cv.cvtColor(img_origin, img_gray, cv.COLOR_RGBA2GRAY, 0); return img_gray; }

                    没错,将彩色RGB图片转换成灰度图用cv.cvtColor(img_origin, img_gray, cv.COLOR_RGBA2GRAY, 0); 就可以啦。

                    但是要注意这里我们用的是cv.cvtColor方法,它的cv.COLOR_RGBA2GRAY传参。

                    上面这段代码执行后,效果如下:

                    4. 对灰度图进行高斯模糊

                    接下来让我们对这张灰度图进行高斯模糊:

                    function GaussianBlur(img_origin) { let img_blurred = new cv.Mat(); let ksize = new cv.Size(5, 5); cv.GaussianBlur(img_origin, img_blurred, ksize, 0); return img_blurred; }

                    在这里,我们用cv.GaussianBlur(img_origin, img_blurred, ksize, 0)完成了图像的高斯模糊。

                    在这里我们使用的(5,5)参数就表示高斯核的尺寸,这个核尺寸越大图像越模糊。但是记住尺寸得是奇数!这是为了保证中心位置是一个像素而不是四个像素。

                    什么高斯模糊?

                    模糊就是一种特殊的滤波,经过这种滤波后图像变得不清晰。我们知道滤波 = 原始图像和掩膜的卷积,当掩膜(窗口)服从高斯分布时,此时我们称这种滤波为高斯滤波,也称为高斯模糊。

                    这样我们就得到一个模糊的乔老爷子:

                    5. 图像二值化

                    接下来到关键的一步啦!让我们对这张模糊过的图片进行二值化:

                    function adaptiveThreshold(img_origin) { let img_threshold = new cv.Mat(); cv.adaptiveThreshold(img_origin, img_threshold, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 5, 2); return img_threshold; }

                    二值化的概念其实很简单,就是对一张图片上的点,像素值大于等于某个值的都直接设为最大值,小于这个值的都直接设为最小值,这样这张图片上每个点都只可能是最大值或最小值其中之一了,其中我们比较的这个数值就是阈值。

                    运行后就可以得到一个二值化的乔老爷子:

                    6.再次对二值化图像进行模糊

                    function img(img_origin, img_target) { let img_gray = cvtColor(img_origin); let ksize1 = new cv.Size(5, 5); let img_blurred1 = GaussianBlur(img_gray, ksize1); let img_threshold1 = adaptiveThreshold(img_blurred1); let img_blurred2 = GaussianBlur(img_threshold1, ksize1); img_target = img_blurred2; cv.imshow('canvasOutput', img_target); }

                    和上面写的一样我们用cv.GaussianBlur()完成了高斯模糊,这样我们就可以得到一个模糊的描边乔老爷子,如下显示:

                    7.再次进行二值化

                    接下来我们对这张图片再次进行二值化:

                    function img(img_origin, img_target) { let img_gray = cvtColor(img_origin); let ksize1 = new cv.Size(5, 5); let img_blurred1 = GaussianBlur(img_gray, ksize1); let img_threshold1 = adaptiveThreshold(img_blurred1); let img_blurred2 = GaussianBlur(img_threshold1, ksize1); let img_threshold2 = threshold(img_blurred2); img_target = img_threshold2; cv.imshow('canvasOutput', img_target); }

                    如何用OpenCV.js制作乔丹动图素描效果教程?

                    8.图像开运算

                    下面让我们去掉图片中一些细小的噪点,这种效果可以通过图像的开运算来实现:

                    function bitwise_not(img_origin) { let img_opening = new cv.Mat(); let M = new cv.Mat(); let ksize = new cv.Size(3, 3); M = cv.getStructuringElement(cv.MORPH_CROSS, ksize); cv.morphologyEx(img_origin, img_opening, cv.MORPH_GRADIENT, M); return img_opening; }

                    要理解图像的开运算就要知道图像的腐蚀和膨胀,所谓的图像腐蚀就是如下的操作,类似于把一个胖子缩小一圈变瘦的感觉:

                    图像膨胀就是腐蚀的反向操作,把图像中的区块变大一圈,把瘦子变成胖子。

                    因此当我们对一个图像先腐蚀再膨胀的时候,一些小的区块就会由于腐蚀而消失,再膨胀回来的时候大块区域的边线的宽度没有发生变化,这样就起到了消除小的噪点的效果。图像先腐蚀再膨胀的操作就叫做开运算。

                    这样下来我们就可以实现对一张彩色图片转换成素描的效果啦!

                    看到这里恭喜大家你已经完成了70%了,下面我们要玩高级一点做动图。

                    10.读取并处理视频中的图像

                    搞定了单张图片,对视频进行处理就非常简单了,只需要将视频里每一帧都做同样的处理再输出即可。

                    首先在开头位置加上读取视频的语句:

                    let video = document.getElementById('videoInput'); let cap = new cv.VideoCapture(video); let frame = new cv.Mat(video.height, video.width, cv.CV_8UC4); let fgmask = new cv.Mat(video.height, video.width, cv.CV_8UC1);

                    然后创建一个setTimeout定时任务,将图像处理的语句都放进去通过上面的方法处理成图片,并通过canvasOutput渲染出来。

                    最后完整代码如下:

                    html 代码:

                    <div> <div class="control"><button id="startAndStop" disabled>Start</button></div> <div class="inputoutput"> <video id="videoInput" src="./mp4/7.mp4"></video> <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>

                    js 代码: 首先要变量声明

                    let streaming = false; let videoInput = document.getElementById('videoInput'); let startAndStop = document.getElementById('startAndStop'); let canvasOutput = document.getElementById('canvasOutput'); let canvasContext = canvasOutput.getContext('2d');

                    代码监听和控制

                    startAndStop.addEventListener('click', () => { if (!streaming) { videoInput.play().then(() => { onVideoStarted(); }); } else { videoInput.pause(); videoInput.currentTime = 0; onVideoStopped(); } }); function onVideoStarted() { streaming = true; startAndStop.innerText = 'Stop'; videoInput.height = videoInput.width * (videoInput.videoHeight / videoInput.videoWidth); video() } function onVideoStopped() { streaming = false; canvasContext.clearRect(0, 0, canvasOutput.width, canvasOutput.height); startAndStop.innerText = 'Start'; } videoInput.addEventListener('canplay', () => { startAndStop.removeAttribute('disabled'); });

                    主要渲染代码:

                    function video() { let video = document.getElementById('videoInput'); let cap = new cv.VideoCapture(video); let frame = new cv.Mat(video.height, video.width, cv.CV_8UC4); let fgmask = new cv.Mat(video.height, video.width, cv.CV_8UC1); const FPS = 30; function processVideo() { try { if (!streaming) { // clean and stop. frame.delete(); fgmask.delete(); return; } let begin = Date.now(); // start processing. cap.read(frame); img(frame, fgmask); // cv.imshow('canvasOutput', fgmask); // schedule the next one. let delay = 1000/FPS - (Date.now() - begin); setTimeout(processVideo, delay); } catch (err) { console.log(err); } }; // schedule the first one. setTimeout(processVideo, 0); }

                    原图:

                    效果如下:

                    Markup

                    <p id="status">OpenCV.js is loading...</p> <div> <div class="control"><button id="startAndStop" disabled>Start</button></div> <div class="inputoutput"> <video id="videoInput" src="./mp4/7.mp4"></video> <img id="imageSrc" alt="No Image" width="100%"/> <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

                    let streaming = false; let videoInput = document.getElementById('videoInput'); let startAndStop = document.getElementById('startAndStop'); let canvasOutput = document.getElementById('canvasOutput'); let canvasContext = canvasOutput.getContext('2d'); let imgElement = document.getElementById('imageSrc'); let inputElement = document.getElementById('fileInput'); inputElement.addEventListener('change', (e) => { imgElement.src = URL.createObjectURL(e.target.files[0]); }, false); imgElement.onload = function() { let img_origin = cv.imread(imgElement); let img_target = new cv.Mat(); img(img_origin, img_target); // cv.imshow('canvasOutput', img_origin); img_origin.delete(); img_target.delete(); }; function img(img_origin, img_target) { let img_gray = cvtColor(img_origin); let ksize1 = new cv.Size(5, 5); let img_blurred1 = GaussianBlur(img_gray, ksize1); let img_threshold1 = adaptiveThreshold(img_blurred1); let img_blurred2 = GaussianBlur(img_threshold1, ksize1); let img_threshold2 = threshold(img_blurred2); let img_opening = bitwise_not(img_threshold2); let ksize2 = new cv.Size(3, 3); let img_opening_blurred = GaussianBlur(img_opening, ksize2); img_target = img_opening_blurred; cv.imshow('canvasOutput', img_target); // img_origin.delete(); } function cvtColor(img_origin) { let img_gray = new cv.Mat(); cv.cvtColor(img_origin, img_gray, cv.COLOR_RGBA2GRAY, 0); return img_gray; } function GaussianBlur(img_origin, ksize) { let img_blurred = new cv.Mat(); // let ksize = new cv.Size(5, 5); cv.GaussianBlur(img_origin, img_blurred, ksize, 0); return img_blurred; } function adaptiveThreshold(img_origin) { let img_threshold = new cv.Mat(); cv.adaptiveThreshold(img_origin, img_threshold, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 5, 2); return img_threshold; } function threshold(img_origin) { let img_threshold = new cv.Mat(); cv.threshold(img_origin, img_threshold, 200, 255, cv.THRESH_BINARY); return img_threshold; } function bitwise_not(img_origin) { let img_opening = new cv.Mat(); let M = new cv.Mat(); let ksize = new cv.Size(3, 3); M = cv.getStructuringElement(cv.MORPH_CROSS, ksize); cv.morphologyEx(img_origin, img_opening, cv.MORPH_GRADIENT, M); return img_opening; } function video() { let video = document.getElementById('videoInput'); let cap = new cv.VideoCapture(video); let frame = new cv.Mat(video.height, video.width, cv.CV_8UC4); let fgmask = new cv.Mat(video.height, video.width, cv.CV_8UC1); const FPS = 30; function processVideo() { try { if (!streaming) { // clean and stop. frame.delete(); fgmask.delete(); return; } let begin = Date.now(); // start processing. cap.read(frame); img(frame, fgmask); // cv.imshow('canvasOutput', fgmask); // schedule the next one. let delay = 1000/FPS - (Date.now() - begin); setTimeout(processVideo, delay); } catch (err) { console.log(err); } }; // schedule the first one. setTimeout(processVideo, 0); } startAndStop.addEventListener('click', () => { if (!streaming) { videoInput.play().then(() => { onVideoStarted(); }); } else { videoInput.pause(); videoInput.currentTime = 0; onVideoStopped(); } }); function onVideoStarted() { streaming = true; startAndStop.innerText = 'Stop'; videoInput.height = videoInput.width * (videoInput.videoHeight / videoInput.videoWidth); video() } function onVideoStopped() { streaming = false; canvasContext.clearRect(0, 0, canvasOutput.width, canvasOutput.height); startAndStop.innerText = 'Start'; } videoInput.addEventListener('canplay', () => { startAndStop.removeAttribute('disabled'); }); let Module = { // emscripten.org/docs/api_reference/module.html#Module.onRuntimeInitialized onRuntimeInitialized() { document.getElementById('status').innerHTML = 'OpenCV.js is ready.'; } }; Module.onRuntimeInitialized();

                    结语

                    其实很简单,大家可以自己实操,最后说几个我遇见的问题:

                    • OpenCV.js文件比较大,解决方法:本地、cdn。
                    • canvas渲染视频需要服务环境,解决方法:node.js。

                    以上就是OpenCV.js实现乔丹动图素描效果图文教程的详细内容,更多关于OpenCV.js乔丹动图素描效果的资料请关注自由互联其它相关文章!

                    本文共计3326个文字,预计阅读时间需要14分钟。

                    如何用OpenCV.js制作乔丹动图素描效果教程?

                    目录 + 背景 + 技术 + OpenCV.js + 优势 + 地点 + 项目搭建 + 准备图片

                    1.引入OpenCV.js,查看OpenCV.js,引入状态

                    2.读取图片并显示

                    3.彩色图片转灰度图

                    4.对灰度图进行高斯模糊

                    5.图像二值化

                    目录
                    • 背景
                    • 技术
                      • OpenCV.js 优点
                      • OpenCV.js 地址
                    • 项目搭建
                      • 准备图片
                      • 1. 引入 OpenCV.js
                        • 查看 OpenCV.js 引入状态
                      • 2. 读取图片并显示
                        • 3. 彩色图片转成灰度图
                          • 4. 对灰度图进行高斯模糊
                            • 5. 图像二值化
                              • 6.再次对二值化图像进行模糊
                                • 7.再次进行二值化
                                  • 8.图像开运算
                                    • 10.读取并处理视频中的图像
                                    • 结语

                                      背景

                                      大家都知道,最近几年大热的AI(人工智能),并且使用AI做人脸识别和物品的分类,其实AI不光可以做这些基本操作,还可以用其来画素描,因为本人是乔丹的篮球粉丝,于是想用AI的技术来实现乔老爷子素描。

                                      技术

                                      因为本人是前端程序猿 爱好 AI,所以我会用前端和AI的方式来实现乔老爷子素描。正好OpenCV.js可以满足我们的需求。

                                      OpenCV.js 优点

                                      OpenCV.js 的出现使得 JavaScript 开发者可以高效便捷的使用 OpenCV 提供的图形处理算法,也就是说开发者仅凭借浏览器就能快速开发诸如图片风格美化、图像识别、OCR等功能的应用。

                                      OpenCV.js 地址

                                      文档:docs.opencv.org/4.x/index.h…

                                      github:github.com/opencv/open…

                                      闲话不多说,今天就让我们跟着乔老爷子一起用OpenCV实现素描效果吧!

                                      项目搭建

                                      准备图片

                                      1. 引入 OpenCV.js

                                      可以直接如下引入,也可以下载到本地,再引入:

                                      <script src="docs.opencv.org/4.x/opencv.js"></script>

                                      查看 OpenCV.js 引入状态

                                      代码如下:

                                      // html <p id="status">OpenCV.js is loading...</p>

                                      // js let Module = { onRuntimeInitialized() { document.getElementById('status').innerHTML = 'OpenCV.js is ready.'; } }; Module.onRuntimeInitialized();

                                      效果,当页面的 loading 变成 read ,说明已完成OpenCV.js加载。

                                      2. 读取图片并显示

                                      html 代码如下:

                                      <div> <div class="inputoutput"> <img id="imageSrc" alt="No Image" width="100%" /> <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>

                                      js 代码如下:

                                      let imgElement = document.getElementById('imageSrc'); let inputElement = document.getElementById('fileInput'); inputElement.addEventListener('change', (e) => { imgElement.src = URL.createObjectURL(e.target.files[0]); }, false); imgElement.onload = function() { let img_origin = cv.imread(imgElement); cv.imshow('canvasOutput', img_origin); img_origin.delete(); };

                                      效果如下图:

                                      然后点击上传图片,上传图片后如下显示:

                                      稍微解释一下上面的代码,首先我们可以本地上传一个图片,通过fileInput获取图片文件,并把图片传给imageSrc渲染,

                                      然后我们利用cv.imread('demo.jpg')读取了这张图片,保存到img_origin这个变量里面。

                                      接下来用cv.imshow('origin', img_origin)将这张照片通过一个canvas显示出来,并且这个窗口的名称叫做canvasOutput

                                      3. 彩色图片转成灰度图

                                      接下来我们要把彩色图片转换成灰度图:

                                      function cvtColor(img_origin) { let img_gray = new cv.Mat(); cv.cvtColor(img_origin, img_gray, cv.COLOR_RGBA2GRAY, 0); return img_gray; }

                                      没错,将彩色RGB图片转换成灰度图用cv.cvtColor(img_origin, img_gray, cv.COLOR_RGBA2GRAY, 0); 就可以啦。

                                      但是要注意这里我们用的是cv.cvtColor方法,它的cv.COLOR_RGBA2GRAY传参。

                                      上面这段代码执行后,效果如下:

                                      4. 对灰度图进行高斯模糊

                                      接下来让我们对这张灰度图进行高斯模糊:

                                      function GaussianBlur(img_origin) { let img_blurred = new cv.Mat(); let ksize = new cv.Size(5, 5); cv.GaussianBlur(img_origin, img_blurred, ksize, 0); return img_blurred; }

                                      在这里,我们用cv.GaussianBlur(img_origin, img_blurred, ksize, 0)完成了图像的高斯模糊。

                                      在这里我们使用的(5,5)参数就表示高斯核的尺寸,这个核尺寸越大图像越模糊。但是记住尺寸得是奇数!这是为了保证中心位置是一个像素而不是四个像素。

                                      什么高斯模糊?

                                      模糊就是一种特殊的滤波,经过这种滤波后图像变得不清晰。我们知道滤波 = 原始图像和掩膜的卷积,当掩膜(窗口)服从高斯分布时,此时我们称这种滤波为高斯滤波,也称为高斯模糊。

                                      这样我们就得到一个模糊的乔老爷子:

                                      5. 图像二值化

                                      接下来到关键的一步啦!让我们对这张模糊过的图片进行二值化:

                                      function adaptiveThreshold(img_origin) { let img_threshold = new cv.Mat(); cv.adaptiveThreshold(img_origin, img_threshold, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 5, 2); return img_threshold; }

                                      二值化的概念其实很简单,就是对一张图片上的点,像素值大于等于某个值的都直接设为最大值,小于这个值的都直接设为最小值,这样这张图片上每个点都只可能是最大值或最小值其中之一了,其中我们比较的这个数值就是阈值。

                                      运行后就可以得到一个二值化的乔老爷子:

                                      6.再次对二值化图像进行模糊

                                      function img(img_origin, img_target) { let img_gray = cvtColor(img_origin); let ksize1 = new cv.Size(5, 5); let img_blurred1 = GaussianBlur(img_gray, ksize1); let img_threshold1 = adaptiveThreshold(img_blurred1); let img_blurred2 = GaussianBlur(img_threshold1, ksize1); img_target = img_blurred2; cv.imshow('canvasOutput', img_target); }

                                      和上面写的一样我们用cv.GaussianBlur()完成了高斯模糊,这样我们就可以得到一个模糊的描边乔老爷子,如下显示:

                                      7.再次进行二值化

                                      接下来我们对这张图片再次进行二值化:

                                      function img(img_origin, img_target) { let img_gray = cvtColor(img_origin); let ksize1 = new cv.Size(5, 5); let img_blurred1 = GaussianBlur(img_gray, ksize1); let img_threshold1 = adaptiveThreshold(img_blurred1); let img_blurred2 = GaussianBlur(img_threshold1, ksize1); let img_threshold2 = threshold(img_blurred2); img_target = img_threshold2; cv.imshow('canvasOutput', img_target); }

                                      如何用OpenCV.js制作乔丹动图素描效果教程?

                                      8.图像开运算

                                      下面让我们去掉图片中一些细小的噪点,这种效果可以通过图像的开运算来实现:

                                      function bitwise_not(img_origin) { let img_opening = new cv.Mat(); let M = new cv.Mat(); let ksize = new cv.Size(3, 3); M = cv.getStructuringElement(cv.MORPH_CROSS, ksize); cv.morphologyEx(img_origin, img_opening, cv.MORPH_GRADIENT, M); return img_opening; }

                                      要理解图像的开运算就要知道图像的腐蚀和膨胀,所谓的图像腐蚀就是如下的操作,类似于把一个胖子缩小一圈变瘦的感觉:

                                      图像膨胀就是腐蚀的反向操作,把图像中的区块变大一圈,把瘦子变成胖子。

                                      因此当我们对一个图像先腐蚀再膨胀的时候,一些小的区块就会由于腐蚀而消失,再膨胀回来的时候大块区域的边线的宽度没有发生变化,这样就起到了消除小的噪点的效果。图像先腐蚀再膨胀的操作就叫做开运算。

                                      这样下来我们就可以实现对一张彩色图片转换成素描的效果啦!

                                      看到这里恭喜大家你已经完成了70%了,下面我们要玩高级一点做动图。

                                      10.读取并处理视频中的图像

                                      搞定了单张图片,对视频进行处理就非常简单了,只需要将视频里每一帧都做同样的处理再输出即可。

                                      首先在开头位置加上读取视频的语句:

                                      let video = document.getElementById('videoInput'); let cap = new cv.VideoCapture(video); let frame = new cv.Mat(video.height, video.width, cv.CV_8UC4); let fgmask = new cv.Mat(video.height, video.width, cv.CV_8UC1);

                                      然后创建一个setTimeout定时任务,将图像处理的语句都放进去通过上面的方法处理成图片,并通过canvasOutput渲染出来。

                                      最后完整代码如下:

                                      html 代码:

                                      <div> <div class="control"><button id="startAndStop" disabled>Start</button></div> <div class="inputoutput"> <video id="videoInput" src="./mp4/7.mp4"></video> <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>

                                      js 代码: 首先要变量声明

                                      let streaming = false; let videoInput = document.getElementById('videoInput'); let startAndStop = document.getElementById('startAndStop'); let canvasOutput = document.getElementById('canvasOutput'); let canvasContext = canvasOutput.getContext('2d');

                                      代码监听和控制

                                      startAndStop.addEventListener('click', () => { if (!streaming) { videoInput.play().then(() => { onVideoStarted(); }); } else { videoInput.pause(); videoInput.currentTime = 0; onVideoStopped(); } }); function onVideoStarted() { streaming = true; startAndStop.innerText = 'Stop'; videoInput.height = videoInput.width * (videoInput.videoHeight / videoInput.videoWidth); video() } function onVideoStopped() { streaming = false; canvasContext.clearRect(0, 0, canvasOutput.width, canvasOutput.height); startAndStop.innerText = 'Start'; } videoInput.addEventListener('canplay', () => { startAndStop.removeAttribute('disabled'); });

                                      主要渲染代码:

                                      function video() { let video = document.getElementById('videoInput'); let cap = new cv.VideoCapture(video); let frame = new cv.Mat(video.height, video.width, cv.CV_8UC4); let fgmask = new cv.Mat(video.height, video.width, cv.CV_8UC1); const FPS = 30; function processVideo() { try { if (!streaming) { // clean and stop. frame.delete(); fgmask.delete(); return; } let begin = Date.now(); // start processing. cap.read(frame); img(frame, fgmask); // cv.imshow('canvasOutput', fgmask); // schedule the next one. let delay = 1000/FPS - (Date.now() - begin); setTimeout(processVideo, delay); } catch (err) { console.log(err); } }; // schedule the first one. setTimeout(processVideo, 0); }

                                      原图:

                                      效果如下:

                                      Markup

                                      <p id="status">OpenCV.js is loading...</p> <div> <div class="control"><button id="startAndStop" disabled>Start</button></div> <div class="inputoutput"> <video id="videoInput" src="./mp4/7.mp4"></video> <img id="imageSrc" alt="No Image" width="100%"/> <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

                                      let streaming = false; let videoInput = document.getElementById('videoInput'); let startAndStop = document.getElementById('startAndStop'); let canvasOutput = document.getElementById('canvasOutput'); let canvasContext = canvasOutput.getContext('2d'); let imgElement = document.getElementById('imageSrc'); let inputElement = document.getElementById('fileInput'); inputElement.addEventListener('change', (e) => { imgElement.src = URL.createObjectURL(e.target.files[0]); }, false); imgElement.onload = function() { let img_origin = cv.imread(imgElement); let img_target = new cv.Mat(); img(img_origin, img_target); // cv.imshow('canvasOutput', img_origin); img_origin.delete(); img_target.delete(); }; function img(img_origin, img_target) { let img_gray = cvtColor(img_origin); let ksize1 = new cv.Size(5, 5); let img_blurred1 = GaussianBlur(img_gray, ksize1); let img_threshold1 = adaptiveThreshold(img_blurred1); let img_blurred2 = GaussianBlur(img_threshold1, ksize1); let img_threshold2 = threshold(img_blurred2); let img_opening = bitwise_not(img_threshold2); let ksize2 = new cv.Size(3, 3); let img_opening_blurred = GaussianBlur(img_opening, ksize2); img_target = img_opening_blurred; cv.imshow('canvasOutput', img_target); // img_origin.delete(); } function cvtColor(img_origin) { let img_gray = new cv.Mat(); cv.cvtColor(img_origin, img_gray, cv.COLOR_RGBA2GRAY, 0); return img_gray; } function GaussianBlur(img_origin, ksize) { let img_blurred = new cv.Mat(); // let ksize = new cv.Size(5, 5); cv.GaussianBlur(img_origin, img_blurred, ksize, 0); return img_blurred; } function adaptiveThreshold(img_origin) { let img_threshold = new cv.Mat(); cv.adaptiveThreshold(img_origin, img_threshold, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 5, 2); return img_threshold; } function threshold(img_origin) { let img_threshold = new cv.Mat(); cv.threshold(img_origin, img_threshold, 200, 255, cv.THRESH_BINARY); return img_threshold; } function bitwise_not(img_origin) { let img_opening = new cv.Mat(); let M = new cv.Mat(); let ksize = new cv.Size(3, 3); M = cv.getStructuringElement(cv.MORPH_CROSS, ksize); cv.morphologyEx(img_origin, img_opening, cv.MORPH_GRADIENT, M); return img_opening; } function video() { let video = document.getElementById('videoInput'); let cap = new cv.VideoCapture(video); let frame = new cv.Mat(video.height, video.width, cv.CV_8UC4); let fgmask = new cv.Mat(video.height, video.width, cv.CV_8UC1); const FPS = 30; function processVideo() { try { if (!streaming) { // clean and stop. frame.delete(); fgmask.delete(); return; } let begin = Date.now(); // start processing. cap.read(frame); img(frame, fgmask); // cv.imshow('canvasOutput', fgmask); // schedule the next one. let delay = 1000/FPS - (Date.now() - begin); setTimeout(processVideo, delay); } catch (err) { console.log(err); } }; // schedule the first one. setTimeout(processVideo, 0); } startAndStop.addEventListener('click', () => { if (!streaming) { videoInput.play().then(() => { onVideoStarted(); }); } else { videoInput.pause(); videoInput.currentTime = 0; onVideoStopped(); } }); function onVideoStarted() { streaming = true; startAndStop.innerText = 'Stop'; videoInput.height = videoInput.width * (videoInput.videoHeight / videoInput.videoWidth); video() } function onVideoStopped() { streaming = false; canvasContext.clearRect(0, 0, canvasOutput.width, canvasOutput.height); startAndStop.innerText = 'Start'; } videoInput.addEventListener('canplay', () => { startAndStop.removeAttribute('disabled'); }); let Module = { // emscripten.org/docs/api_reference/module.html#Module.onRuntimeInitialized onRuntimeInitialized() { document.getElementById('status').innerHTML = 'OpenCV.js is ready.'; } }; Module.onRuntimeInitialized();

                                      结语

                                      其实很简单,大家可以自己实操,最后说几个我遇见的问题:

                                      • OpenCV.js文件比较大,解决方法:本地、cdn。
                                      • canvas渲染视频需要服务环境,解决方法:node.js。

                                      以上就是OpenCV.js实现乔丹动图素描效果图文教程的详细内容,更多关于OpenCV.js乔丹动图素描效果的资料请关注自由互联其它相关文章!