本教程介绍了如何使用opencv生成一副简笔画视频,包括片头、如何做画等。

1、视频包括:

(1)片头:包括学号姓名,同时会出现"I Love CV"在学号和姓名的中央,而且他们是以动画方式“飞入”视频的,其中姓名从顶部“飞”到屏幕1/3处,学号信息从下“飞”到1/3处,I LOVE CV从左向右飞入。在片头显示完后,会停顿越三秒钟后,片头消失,正片开始。

下图为片头停顿处截图:

(2)正片:正片主要画了一头可爱的小熊和一头胖胖的小猪以及一个桃心(预示着小熊.....),其中所有的镜头最小单位都是像素,是一个点一个点画计算并画出的,并没有调用内置的画图函数(画点函数除外)以下是最终效果截图:

一、开发环境

1、开发环境:vs2015

2、Opencv库:opencv2.4

3、操作系统:windows10

二、实现方法

我把整个实现分为三步:

初始化、工具函数的编写、画图

下面将分开说明各部分实现步骤:

1、初始化:首先定义两个全局变量ViedoWriter writer和Mat image,并对其初始化,分别在规定路径创建一个空视频(writer)和空矩阵或图片(image)。我的想法是一个点一个点的画图,所以我需要每画一个点或者一个规定步长的点就网writer里写一帧,所以我封装了一个函数putPicture(Mat img)用于将参数传入writer中。在以后的画图工具函数中,我每描出一个点就调用一次putPicture函数。

2、对于工具函数的撰写,我主要写了以下几个函数:

(1)drawPoint(Mat img, Point center,Scalar color,int thick)

功能:可以再指定的center上画不同大小的点(大小由thick参数指定)。该函数是画所有图的核心函数

实现:调用opencv的circle函数

(2)drawLine(Mat mat, Point start, Point end,Scalar color,int thick)

功能:通过起始终止点画出一条线段并将每个点以一帧的形式存入视频。

实现:使用DDA算法画直线。

改进:DDA有舍入误差会影响精度,可以使用bersenham算法,但我没有时间了。。。

(3)drawArc(Mat img, Point center, double radius, double start_angle, double end_angle, Scalar color,int thick)

功能:通过给定参数逐点画圆弧并将每个点以一帧的形式存入视频。

实现:用圆的参数方程逐点描出

改进:可使用bersenham算法,但我个人觉得针对此问题没必要,增加很多算法上的负担。因为此问题不太要求精度。

(4)drawEarc(Mat img, Point center, double radius, double start_angle, double end_angle, float a,float b,Scalar color,int thick,bool is_x)

功能:通过给定参数画椭圆弧并将每个点以一帧的形式存入视频,其中通过is_x变量可以指定焦点位置,同时thick可以指定宽度,color指定颜色

实现:同样使用参数方程

(5)drawStar(Mat img,Point center,int a,Scalar color,int thick)

功能:通过给定参数画心形并将每个点以一帧的形式存入视频,其中a可指定心形的大小。

实现:

arc.x = center.x + a*i*sin(PI*sin(i) / i);

arc.y = center.y + a*abs(i)*cos(PI*sin(i) / i);

并没有使用经典的笛卡尔心形公式,而是使用的这个形状更好看的参数方程。

(6)drawBackground(bool flag)

功能:画一个白色的大矩形覆盖整个屏幕,起到画背景和清屏的作用

3、有了以上制作视频思路和工具最后的画图部分考验的更多的是时间,我主要分了三部分来画

(1)drawBear()

功能:顾名思义画熊。对于这个萌萌哒的小熊:

他的身子是椭圆的一部分弧,耳朵是圆的一部分,鼻子是一个小椭圆但是我增加了线的厚度。

改进:需要改进的部分太多了,由于我是“凭空”使用我的工具画的,并没有使用ps等工具具体的挖出精确的点来画,所以导致很多部分无法完成。这也导致只熊的身子和腿很丑。

(2)drawRh()

功能:画猪

这个猪的构造很简单,我没有选择有复杂曲线的猪,选择了这个可以由圆构成的猪。

改进:可以使用参数曲线算法来丰富他的身体。

(3)drawText()

功能:制作片头

实现方法:使用内置的puttext函数,加上清屏函数组合来完成文字的滑动,即每移动一次字幕调用清屏函数,最后使用临时变量保存的算法使三行字幕停顿几秒钟。

三、心得体会与优缺点:

缺点与不足:

1、没有对于中文的处理,本来学号和姓名我很想使用中文的,但是opencv不支持,后来又使用freetype包却出现很多编译错误,没办法由于时间紧迫没有实现

2、画图工具封装的太少,只做了几个最基本的函数,对于高级的函数如参数曲线等由于能力问题并没有用到

3、没有对颜色的处理

下面附上源代码:

#include <opencv2/opencv.hpp>
#include<string>
#include<io.h>
#include<math.h>
#include"base.h"
using namespace std;
using namespace cv;
#define NUM_FRAME 300
#define SIZE 5
#define W 1080
#define H 720
#define PI 3.1415926
char path[100];//输入文件路径
VideoWriter writer;
Mat image,temp;
Point s, e;
void convert(Point &a)
{a.x = a.x + W / 2;a.y = -a.y + H / 2;
}
void rconvert(Point &a)
{a.x = a.x - W / 2;a.y = -a.y + H / 2;
}void init()
{//image= Mat::zeros(W, W, CV_8UC3);//创建一张空图像image = Mat(H, W, CV_8UC3);temp = Mat(H, W, CV_8UC3);strcpy(path, "G:\\image\\viedo.avi");writer = VideoWriter(path, CV_FOURCC('X', 'V', 'I', 'D'), 30, Size(W, H));
}
void putPicture(Mat img)
{writer.write(Mat(img));
}
void delay(int k)
{for (int i = 0; i <= k; i++){putPicture(image);}
}
void play()
{VideoCapture capture(path);if (!capture.isOpened())cout << "fail to open!" << endl;////获取整个帧数//long totalFrameNumber = capture.get(CV_CAP_PROP_FRAME_COUNT);//cout << "整个视频共" << totalFrameNumber << "帧" << endl;//设置开始帧()long frameToStart = 0;capture.set(CV_CAP_PROP_POS_FRAMES, frameToStart);cout << "从第" << frameToStart << "帧开始读" << endl;//获取帧率double rate = capture.get(CV_CAP_PROP_FPS);cout << "帧率为:" << rate << endl;//承载每一帧的图像
    Mat frame;//显示每一帧的窗口namedWindow("Viedo");//两帧间的间隔时间:int delay = 1000 / rate;long currentFrame = frameToStart;while (1){//读取下一帧if (!capture.read(frame)){break;return;}//这里加滤波程序imshow("Extracted frame", frame);int c = waitKey(delay);//按下按键后会停留在当前帧,等待下一次按键if (c >= 0){waitKey(0);}currentFrame++;}//关闭视频文件
    capture.release();
}
void drawLine(Mat mat, Point start, Point end,Scalar color,int thick)
{//printf("start Point: x=%d y=%d\n", start.x, start.y);
    convert(start);convert(end);int x1, y1,step;Point center=start;x1 = start.x;y1 = start.y;double footx,footy;int dx = end.x - start.x;int dy = end.y - start.y;drawPoint(mat, center, color,thick);putPicture(mat);if (abs(dx) > abs(dy)){step = abs(dx);}else {step = abs(dy);}footx = (double)dx / step;footy = (double)dy / step;//printf("footy = %f\n", footy);for (int i = 0; i<step; i++){if (footx > 0) {x1 += int(footx + 0.5);}if (footx < 0){x1 += int(footx - 0.5);}if (footy > 0){y1 += int(footy + 0.5);}if (footy < 0){y1 += int(footy - 0.5);}center.x = x1;center.y = y1;drawPoint(mat, center, color,thick);//printf("x=%d y=%d\n", center.x, center.y);
        putPicture(mat);}rconvert(center);//printf("end Point: x=%d y=%d\n", center.x, center.y);//printf("\n");
}
void drawLine2(Mat mat, Point start, Point end, Scalar color,int thick)
{convert(start);convert(end);int x1, y1, step;double k;Point center = start;x1 = start.x;y1 = start.y;int dx = end.x - start.x;int dy = end.y - start.y;if (dx != 0){k = dy / dx;}elsek = 0;double d = k - 0.5;drawPoint(mat, center, color,thick);printf("start Point: x=%d y=%d\n", center.x, center.y);putPicture(mat);while(x1!=end.x){x1++;if (d >= 0){y1++;d = d + k - 1;}else{d = d + k;}center.x = x1;center.y = y1;drawPoint(mat, center, color,thick);//printf("x=%d y=%d\n", center.x, center.y);
        putPicture(mat);}printf("end Point: x=%d y=%d\n", center.x, center.y);
}
void drawBackground(bool flag)
{rectangle(image,Point(0, 0),Point(W, W),Scalar(255, 255, 255),-1,8);if (flag == true){putPicture(image);}rectangle(image,Point(0, 550),Point(W, W),Scalar(0, 255, 0),-1,8);
}
void drawText()
{int i = 0;int count = 30;String name = "name    :   Sunke";String number = "Student ID: 317040001";String other = "I Love CV";while(1){i++;putText(image, number, Point(W / 3,H-i*(H/3)/count), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 0, 0));putText(image, name, Point(W/3, 0 + i*(H / 3) / count), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255));putPicture(image);if (i == count){image.copyTo(temp);for (int j = 0; j <= count; j++){temp.copyTo(image);putText(image, other, Point(75+j*(W/3)/count, H/2), CV_FONT_HERSHEY_TRIPLEX, 1.5, Scalar(0, 255, 0));putPicture(image);if (j == count)//片头延时
                {delay(200);}drawBackground(false);}break;}else{drawBackground(false);//只是重置image变量,并不画这样避免了闪屏
        }}putPicture(image);
}
void drawArc(Mat img, Point center, double radius, double start_angle, double end_angle, Scalar color,int thick)
{convert(center);Point arc;double foot = 0.02;for (double r = start_angle; r <= end_angle; r = r + foot){arc.x = center.x + radius*cos(r);arc.y = center.y + radius*sin(r);if (r == start_angle){s = arc;}if (r == end_angle){s = arc;}drawPoint(img, arc, color,thick);putPicture(image);}
}
void drawEarc(Mat img, Point center, double radius, double start_angle, double end_angle, float a,float b,Scalar color,int thick,bool is_x)
{convert(center);Point arc;double foot=0.02;for (double r = start_angle; r <= end_angle; r = r + foot){if (is_x){arc.x = center.x + a*cos(r);arc.y = center.y + b*sin(r);}else{arc.x = center.x + b*cos(r);arc.y = center.y + a*sin(r);}if (r == start_angle){s = arc;}if (r == end_angle){s = arc;}drawPoint(img, arc, color,thick);putPicture(image);}
}
void drawBear()
{Point left_eye(190, 160);Point right_eye(230, 160);convert(left_eye);convert(right_eye);drawLine(image, Point(150, 100), Point(150, 180), Scalar(0, 0, 0),1);//drawLine(image, Point(150, 220), Point(190, 200), Scalar(0, 0, 0),1);drawArc(image, Point(165, 180), 15, PI,2*PI,Scalar(0, 0, 0), 1);drawEarc(image, Point(210, 180), 50, PI, 2 * PI, 30, 8, Scalar(0, 0, 0),1,true);drawArc(image, Point(255, 180), 15, PI, 2 * PI, Scalar(0, 0, 0), 1);//drawLine(image, Point(230, 180), Point(270, 220), Scalar(0, 0, 0),1);drawLine(image, Point(270, 180), Point(270, 100), Scalar(0, 0, 0),1);//脸drawPoint(image, left_eye, Scalar(0, 0, 0),5);drawPoint(image, right_eye, Scalar(0, 0, 0),5);putPicture(image);drawEarc(image, Point(210, 140), 50, 0, 2 * PI, 6, 3, Scalar(0, 0, 0),5,true);drawLine(image, Point(210, 143), Point(210, 125), Scalar(0, 0, 0), 1);drawLine(image, Point(210, 125), Point(200, 115), Scalar(0, 0, 0), 1);drawLine(image, Point(210, 125), Point(220, 115), Scalar(0, 0, 0), 1);//手drawLine(image, Point(150, 100), Point(90, 0), Scalar(0, 0, 0), 1);drawLine(image, Point(270, 100), Point(330, 0), Scalar(0, 0, 0), 1);//左drawLine(image, Point(50, 0), Point(70, -20), Scalar(0, 0, 0), 1);drawLine(image, Point(70, -20), Point(150, 40), Scalar(0, 0, 0), 1);//右drawLine(image, Point(370, 0), Point(350, -20), Scalar(0, 0, 0), 1);drawLine(image, Point(350, -20), Point(270, 40), Scalar(0, 0, 0), 1);//身体//左drawEarc(image, Point(155, -40), 50, -1.5*PI, -0.5*PI, 100, 30, Scalar(0, 0, 0), 1,false);drawLine(image, Point(155, -140), Point(190, -140), Scalar(0, 0, 0), 1);drawLine(image, Point(190, -140), Point(190, -90), Scalar(0, 0, 0), 1);//右drawEarc(image, Point(265, -40), 50, -0.5*PI, 0.5*PI, 100, 30, Scalar(0, 0, 0), 1, false);drawLine(image, Point(270, -140), Point(240, -140), Scalar(0, 0, 0), 1);drawLine(image, Point(240, -140), Point(240, -90), Scalar(0, 0, 0), 1);//drawLine(image, Point(190, -90), Point(240, -90), Scalar(0, 0, 0), 1);drawEarc(image, Point(215, -90), 50, PI, 2 * PI, 25, 8, Scalar(0, 0, 0), 1, true);}
void drawStar(Mat img,Point center,int a,Scalar color,int thick)
{convert(center);Point arc;double foot=2*PI/360;for (double i = -PI; i <= PI; i=i+foot){/*arc.x = center.x + a*(2 * cos(i) - cos(2 * i));arc.y = center.y + a*(2 * sin(i) - sin(2 * i));*/arc.x = center.x + a*i*sin(PI*sin(i) / i);arc.y = center.y + a*abs(i)*cos(PI*sin(i) / i);drawPoint(img, arc, color, thick);putPicture(image);}
}
void drawRh()
{Point left_eye(-240, 160);Point right_eye(-180, 160);Point left_nose(-240,85);Point right_nose(-180,85);convert(left_eye);convert(right_eye);convert(left_nose);convert(right_nose);drawArc(image, Point(-210, 130), 100, 0, 2 * PI, Scalar(0, 0, 0), 1);//眼眶drawArc(image, Point(-170, 170), 20, 0, 2 * PI, Scalar(0, 0, 0), 1);drawArc(image, Point(-250, 170), 20, 0, 2 * PI, Scalar(0, 0, 0), 1);//眼球drawPoint(image, left_eye, Scalar(0, 0, 0), 6);putPicture(image);drawPoint(image, right_eye, Scalar(0, 0, 0), 6);putPicture(image);//鼻子drawEarc(image, Point(-210, 85), 50, 0, 2 * PI, 60, 30, Scalar(0, 0, 0), 1, true);//鼻孔drawPoint(image, left_nose, Scalar(0, 0, 0), 9);putPicture(image);drawPoint(image, right_nose, Scalar(0, 0, 0), 9);putPicture(image);//左耳朵drawLine(image, Point(-280, 207), Point(-280, 240), Scalar(0, 0, 0), 1);drawLine(image, Point(-280, 240), Point(-260, 220), Scalar(0, 0, 0), 1);//右耳朵drawLine(image, Point(-140, 207), Point(-140, 240), Scalar(0, 0, 0), 1);drawLine(image, Point(-140, 240), Point(-160, 220), Scalar(0, 0, 0), 1);//身子drawEarc(image, Point(-210, 95), 170, 0, 2*PI, 185,160,Scalar(0, 0, 0), 2,true);//脚drawArc(image, Point(-290, -80), 30, PI, 2 * PI, Scalar(0, 0, 0), 1);drawLine(image, Point(-320, -80), Point(-260, -80), Scalar(0, 0, 0), 1);drawArc(image, Point(-130, -80), 30, PI, 2 * PI, Scalar(0, 0, 0), 1);drawLine(image, Point(-160, -80), Point(-100, -80), Scalar(0, 0, 0), 1);}
int main()
{printf("正在生成视频,请稍后");init();drawBackground(true);drawText();drawBear();drawRh();drawStar(image, Point(0, 300), 40, Scalar(255, 255, 0), 2);drawStar(image, Point(300, 300), 50, Scalar(255, 0, 255), 2);drawStar(image, Point(0, 0), 35, Scalar(255, 0, 0), 2);drawStar(image, Point(-350, 250), 35, Scalar(255, 0, 255), 2);imshow("pig", image);play();waitKey();return 0;
}

base.cpp

#include"base.h"
#include<math.h>void MyLine(Mat img, Point start, Point end)
{int thickness = 2;int lineType = 8;line(img,start,end,Scalar(255, 255, 255),thickness,lineType);
}
void drawPoint(Mat img, Point center,Scalar color,int thick)
{circle(img,center,thick,color,-1);
}
void drawEye(Mat img, Point center, Scalar color)
{circle(img,center,5,color,-1);
}

转载于:https://www.cnblogs.com/SK1997/p/8042506.html

计算机视觉之--使用opencv生成简笔画小视频相关推荐

  1. 分享Canvas简笔画小程序源码

    效果预览 小程序里面的一些处理图片的应用,都是通过Canvas组件实现的.小游戏也是基于Canvas实现的,比如H5小游戏,或微信小游戏. Canvas技术不仅可以绘制出基本的图形,还可以制作出炫酷的 ...

  2. python简笔画教程视频_只用C++和Python,让你的简笔画实时动起来!

    大数据文摘出品作者:刘俊寰让蒙娜丽莎笑起来对AI来说已经不是什么新鲜事了.试想,如果在画纸上创作的图像能够实时地生成动画,达芬奇可能会吓个半死.没错,文摘菌今天要给大家介绍的,就是捷克技术大学和Sna ...

  3. HTML绘制小房子,简笔画教程怎么画小房子

    房子是很多人刚学画画的时候较为爱画的,画起来也算是比较的简单,简笔画也是幼儿们非常喜欢的绘画方法,爸爸妈妈们可以多陪陪孩子画一画简笔画,那么房子简笔画怎么画?下面我们就一起来看看小房子简笔画图解教程. ...

  4. 基于 C++ OpenCV 生成小视频【100010476】

    制作个人小视频 一.实验内容和要求 基于 OpenCV 生成小视频,制作有浙大元素的图片和个人信息的片头,自己设计情节,其中要缓慢地画一张画面,最后自己设计一个片尾. 做了一个火柴人初见了 OpenC ...

  5. 线条边框简笔画图片大全_每天学一幅简笔画生活小物简笔画图片大全!

    点击上方蓝色字体关注「每天学一幅简笔画」 11111111111111111111111111111111111111111111111111111111111111111111111111111观自 ...

  6. 工业动画制作过程介绍(二)——两张静态简笔画生成动画

    在文章<工业动画制作过程介绍(一)--静态简笔图画的制作>中介绍了如何将一张机械照片转化为简笔画的过程,今天介绍把第二张机械图片转化为简笔画的过程,并且把两张简笔画生成一个动画的过程. 目 ...

  7. 【报名截止,招募结束】 | 零基础入门简笔画之小插画——21天训练营第三期...

    报名截止,请勿打赏. 招募结束,谢谢关注. 文:铃铛子经纪人 你是否也有过绘画梦?但总被这些想法阻碍,觉得学好画画好难. 零基础的成年人-- 难道就不能用画笔去描述.创造世界了吗? --画画属于每一个 ...

  8. 教程 |10分钟成为简笔画达人 9 (一大波蠢萌小动物来袭)

    也许,我们都一样,并非科班出身,不是根正苗红的艺术苗子.但是爱好二字让我们在这条路上不断前行. 对于刚刚接触画画的人来说,经常会觉得自己画的不够好,线条不直,形状不美,解决这些问题除了需要多多观察.时 ...

  9. 教程 | 10分钟入门简笔画(彩色小插画)

    你好,色彩. BY:铃铛子 马克笔的笔触感觉: BY:铃铛子 由于大家写字的时候,为了笔锋,会起笔停顿一下,落笔再停顿一下,但是运行马克笔的时候不要这样,起笔确定了就画线,落笔除非必要,否则不停顿. ...

最新文章

  1. hello this Word ! I'm coming!
  2. [文档].艾米电子 - 二进制计数器及其变体,Verilog
  3. 64位Win10安装Pytorch
  4. Python应用实战案例-深入浅出Python随机森林预测实战(附源码)
  5. 【机器学习基础】前置知识(五):30分钟掌握常用Matplotlib用法
  6. 掌握 Ajax,第 11 部分: 服务器端的 JSON
  7. 使用拷贝的方式(adb push) 绕过Android系统和adb install直接安装APK
  8. TextView的跑马灯效果(AS开发实战第二章学习笔记)
  9. SpringCloud 实战:禁止直接访问后端服务
  10. linux tick异常变化,linux tickGet()
  11. (转载)突然就看懂了《大话西游》
  12. 查看linux中某个端口(port)是否被占用***
  13. .NET下解析Json的方法
  14. 《Expert C Programming》(C专家编程)读书笔记
  15. android bugly qq,Android如何快速集成腾讯Bugly
  16. 内网渗透学习-Windows信息收集
  17. oracle 11g duplicate database基于备份复制数据库(五)
  18. 我的第一个油猴脚本--微博超话自动签到
  19. SpringBoot的controller为什么不能并行执行?同一个浏览器连续多次访问同一个url竟然是串行的?- 第329篇
  20. 【AI实战】手把手教你深度学习文字识别(文字检测篇:基于MSER, CTPN, SegLink, EAST等方法)...

热门文章

  1. android n进入分屏代码分析_Android分屏多窗口的实践代码
  2. cad多段线画圆弧方向_(cad多段线画圆弧方向)在cad中如何使用excel画样条曲线
  3. kaggle 注册无法激活的问题解决
  4. 解决方法:CC2640R2F从7x7改成5x5封装,主机连接失败
  5. 小米4 miui专用 Xposed安装器86版
  6. Lenovo system x3500 m5 安装显卡
  7. godot 外部编辑器配置
  8. PPT画图保存时自动压缩图片问题
  9. linux国际象棋,国际象棋通用引擎协议
  10. 团队协作之 Git 提交