zoukankan      html  css  js  c++  java
  • CV HW1

    开发软件说明:

    OpenCV 2.1.0

    Visual Studio 2019

    1. 内容简介

    • 本次作业实现生成一个视频,包含片头,中间动画,片尾动画三部分,然后读取生成的视频并按下空格可以暂停
      • 片头是个人信息+倒计时
      • 中间动画,画了一个小猪佩奇追气球的故事
      • 片尾动画,是四个彩色方块交替出现

    2. 视频生成过程

    • 创建视频

      • 使用VideoWrite类,生成一个名叫test.avi的视频,同时配置大小,帧率等参数

        VideoWriter video("test.avi", CV_FOURCC('X', 'V', 'I', 'D'), 270, Size(1280, 720));
        
    • 制作片头

      • 片头是由几个图片组合而成的,需要把图片作为视频中的一帧,插入进去

        • 第一张封面是HW1
        • 第二张是我的个人信息和含有校徽的背景
        • 第三张是我的个人照片(5岁)
        • 第四到六张是一个倒计时
        • 第七张是Let's start,表示动画开始
      • 设计delay函数,可以在video中,插入time数量个image图片

        void delay(Mat image, VideoWriter video, int time) {
        	for (int i = 0; i < time; i++) {
        		video << image;
        	}
        }
        
      • 同时图与图的切换,本次实验中设计了百叶窗切换方法

        • 其原理就是在图片1中根据一定规律载入图片2的像素,生成一帧图片,再插入到video中
        • 百叶窗实现要点:
          • 将图形中点的y坐标分为5层,每一层相隔为r,5层像素一起由pic0变为pic1,实现百叶窗变换
        • 注意两个矩阵赋值时,因为是3通道,所以每一像素要赋三个值
        void blindTransition(Mat pic0, Mat pic1, VideoWriter video) {          // 百叶窗载入
        	int x_max = pic0.cols, y_max = pic0.rows;
        	int y_step = y_max / 5;                        
        	for (int r = 0; r < y_step; r++) {              
        		for (int y = r; y < y_max; y += y_step) {  
        			uchar* data = pic0.ptr<uchar>(y);      
        			uchar* p1 = pic1.ptr<uchar>(y);         
        			for (int x = 0; x < x_max; x++) {       
        				data[3 * x] = p1[3 * x];            
        				data[x * 3 + 1] = p1[x * 3 + 1];
        				data[x * 3 + 2] = p1[x * 3 + 2];
        			}
        		}
        		for (int i = 0; i < 3; i++) {
        			video << pic0;
        		}
        	}
        }
        
      • 实现上述两个准备函数后,就可以读入已有的图片,经过百叶窗切换形成视频

        • 在插入图片之前要将图片的size设为一致,否则会出现矩阵数组溢出的情况

          	for (size_t i = 2; i <= count; i++)
          	{
          		stringstream str1, str2;
          		str1 << i-1 << ".png";
          		str2 << i << ".png";
          		Mat image1 = imread(img_path + str1.str());
          		Mat image2 = imread(img_path + str2.str());
          		if (!image1.empty() && !image2.empty())
          		{
          			resize(image1, image1, Size(1280, 720));
          			resize(image2, image2, Size(1280, 720));
          			blindTransition(image1, image2, video);
          
          			//让第二帧停留的久一点
          			if (i == 2) {
          				delay(image2, video, 50);
          			}
          			video << image2;
          			cout << "正在处理第" << i << "帧" << endl;
          		}
          	}
          
    • 制作动画

      • 作业中设计的动画内容是小猪佩奇追气球的情节,分为以下几个部分

        • 画小猪佩奇和气球
        • 小猪佩奇带着气球向右走
        • 小猪佩奇不动,气球向左飞
        • 小猪佩奇向左走追气球
        • 小猪佩奇追不到气球,在画面中间静止,并变成哭脸
      • 需要的函数

        • void drawEarc(Mat img, VideoWriter video, Point center, double radius, double start_angle, double end_angle, float a, float b, Scalar color, int thick, bool is_x, bool is_drawing)

          • 参数

            • 在img上绘制椭圆
            • 椭圆的圆点在center,弧度为radius, 起始度数为start_angle, 终点度数为end_angel, 长半轴(水平)为a, 短半轴(竖直)为b
            • 颜色为color, 线的宽度为thick
            • is_drawing代表是否把img插入video
          • 应用

            • 如果画横线或竖线,可以令短半轴或长半轴为0, 绘制度数为(PI, 2*PI)或(0.5 * PI, 1.5 * PI)
            • 画弧线或圆可以调整参数画出适合的图案
          • 实现

            • 在其中,应用椭圆的一些公式进行绘制

              	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);
              
        • Mat drawPeppa(Mat image, VideoWriter video, int x, int y, bool is_drawing, int frame, bool is_cry)

          • 参数

            • 实现在image上绘制佩奇,并把Image插入video
            • 以Point(x, y)作为佩奇的左上角进行绘制
            • is_drawing代表是否显示画的过程
            • 因为动画中有佩奇走路,frame代表当前走路是第几帧,一共有3帧,站着,抬左腿,抬右腿
            • is_cry代表当前佩奇是哭脸还是笑脸
            • 函数中所有的线条都是用drawEarc来实现的
          • 实现步骤,这里以佩奇的头为例

            	//佩奇的头
            	drawEarc(image, video, Point(x + 265, y + 150), 50, 0.2 * PI, 0.6 * PI, 30, 30, Scalar(0, 0, 0), 1, true, is_drawing);
            	drawEarc(image, video, Point(x + 210, y + 180), 50, 0, PI, 50, 50, Scalar(0, 0, 0), 1, true, is_drawing);
            	drawEarc(image, video, Point(x + 250, y + 180), 50, PI, 1.6 * PI, 90, 50, Scalar(0, 0, 0), 1, true, is_drawing);
            	drawEarc(image, video, Point(x + 282, y + 150), 50, 0, 2 * PI, 19, 19, Scalar(0, 0, 0), 1, true, is_drawing);
            

            画出佩奇的头,如下

            image-20201130162045355.png

            同理画出身体和其他细节

          • 实现佩奇走路

            共有3中情况,站着,抬左腿,抬右腿,只要循环实现站着->抬左腿->站着->抬右腿,就能实现佩奇走路了。

        • Mat drawballon(Mat image, VideoWriter video, int x, int y, bool is_drawing)

          • 实现在image上绘制气球,并把image插入video
          • 以Point(x, y)作为气球的左上角进行绘制
          • is_drawing代表是否显示画的过程
        • Mat convertPappe(Mat image, Mat result, int c_x)

          • 翻转佩奇,把image中的像素点以x = c_x这条直线进行翻转,结果存放在result中
      • 绘制的过程

        • 根据之前设计的动画情节,在不同的坐标上绘制图形,以下以前两个情景的代码为例,其他情景类似,只需要控制佩奇和气球的不同坐标即可

        • 初始化并绘制佩奇

          • //初始化画板
              	Mat image = Mat(Size(1280, 720), CV_8UC3);
              	
              	//绘制佩奇和气球
              	drawPeppa(image, video, 400, 200, true, 0, false);
              	drawballon(image, video, 400, 200, true);
              	delay(image, video, 5);
            
        • 佩奇带着气球右走5步

          • 通过drawPeppa函数中参数frame的值来控制佩奇的腿实现走路的动作
          	//佩奇往右走5步
          	int location1;
          	for (location1 = 0; location1 < 4 * 5; location1++) {
          		Mat image = Mat(Size(1280, 720), CV_8UC3);
          		image = drawPeppa(image, video, 400 + location1 * 10, 200, false, location1 % 4, false);
          		image = drawballon(image, video, 400 + location1 * 10, 200, false);
          		delay(image, video, 10);
          	}
          
    • 片尾动画

      • 片尾动画是画面中间4个不同颜色的小正方形交替变换

      • 关键函数Mat drawBox(Mat image, int x, int y, int B, int G, int R)

        • 在image上, 以Point(x, y)为左上角,画一个边长为50像素,颜色为Scalar(B, G, R),的正方形
      • 实现

        • 交替出现四个方块, 共10个循环

          	for (int i = 0; i < 4 * 10; i++) {
          		Mat image_end = Mat(Size(1280, 720), CV_8UC3);
          		if (i % 4 == 0)		//blue
          			image_end = drawBox(image_end, -60, -60, 0x2d, 0x85, 0xf0);
          		else if (i % 4 == 1)		//red
          			image_end = drawBox(image_end, -60, 0, 0xf4, 0x43, 0x3c);
          		else if (i % 4 == 2)		//yellow
          			image_end = drawBox(image_end, 0, 0, 0xff, 0xbc, 0x32);
          		else if (i % 4 == 3)		//green
          			image_end = drawBox(image_end, 0, -60, 0xa, 0xa8, 0x58);
          		delay(image_end, video, 80);
          	}
          

    3. 视频读取过程

    • 读取视频文件

      • 使用VideoCapture类, 读取之前生成的视频test.avi
    • 展示每一帧

      • 读取每一帧,再使用imshow函数输出每一帧
    • 设置空格暂停

      • 如果没有按键,waitKey(delay)返回-1,不执行waitKey(0),进入下一次循环。

      • 如果有按键,返回按键的ASCII值,waitKey(delay)>=32为true,执行waitKey(0),程序暂停,直到有键盘输出才进行下一次循环。

      • int delay = 4;
        if (delay >= 0 && waitKey(delay) >= 32)
        		waitKey(0);
        
    • 使用release方法,释放资源

    4. 实验结果展示与分析

    • 百叶窗切换

      • 下图就是第一帧和第二帧的切换,可以看到实现了百叶窗的效果

      (包含个人信息,这张图就不放了)

    • 绘制佩奇的过程

      • 可以看到下图中,逐步画出佩奇的效果

        image-20201130163307911.png

        image-20201130163328956.png

        image-20201130163406035.png

    • 一些动画的场景

      • 佩奇回头

        image-20201130163511846.png

      • 佩奇哭脸

        image-20201130163541350.png

      • 佩奇走路

        这里图片不能表现出来,详见视频

    • 片尾

      • 如下的四个彩色方块循环出现消失,组成了片尾

      image-20201130163659383.png

      image-20201130163720609.png

    5. 编程体会

    • 本次作业中,我了解了opencv最基础的应用,比如读图片,读视频,生成视频,把图像一帧一帧插入图像等等
    • 还学会了把一些简单的图形计算公式应用于图像显示上面,比如画椭圆, 画方块等等
    • 还学会了一些基本的画图和矩阵操作,最基本的图形变换,比如百叶窗变换,图像翻转等
    • 最后还学会通过简单的帧的变换做一些动画,比如小猪佩奇走路,最后的片尾动画

    借鉴的网页 https://blog.csdn.net/u013794793/article/details/78787409

  • 相关阅读:
    笔记35 跨重定向请求传递数
    判断邮箱的正则表达式
    按钮
    async await 的用法
    笔记34 Spring MVC的高级技术——处理multipart形式的数据
    Convert Sorted Array to Binary Search Tree
    Binary Tree Zigzag Level Order Traversal
    Unique Binary Search Trees,Unique Binary Search Trees II
    Validate Binary Search Tree
    Populating Next Right Pointers in Each Node,Populating Next Right Pointers in Each Node II
  • 原文地址:https://www.cnblogs.com/CGCY/p/14102662.html
Copyright © 2011-2022 走看看