homework1

  • 作业要求

    对输入的一个彩色视频与五张以上照片,用OpenCV实现以下功能或要求:

    1. 命令行格式: " xxx.exe 放视频与照片的文件夹路径" ,(例如MyMakeVideo.exe C:\input )【 假设该文件夹下面只有一个avi视频文件与若干jpg文件】

    2. 将输入的视频与照片处理成同样长宽后,合在一起生成一个视频;

    3. 这个新视频中,编程生成一个片头,然后按幻灯片形式播放这些输入照片,最后按视频原来速度播放输入的视频;

    4. 新视频中要在底部打上含自己学号与姓名等信息的字幕;

    5. 有能力的同学,可以编程实现镜头切换效果;

  • 代码

#include <iostream>

#include <string>

#include <vector>

#include <sstream>

#include <opencv2\opencv.hpp>

#include <windows.h>

#include <math.h>

using namespace std;

using namespace cv;

#define WINDOWN_NAME "Video Output"

#define INTERVAL (fps * 2.5)

   

VideoCapture capture;

VideoWriter writer;

int width = 1280, height = 728, fps = 25;

RNG rng;

vector<string> vec;

   

//放文字

void putTextOnImg(Mat img)

{

string strHint = "w*d : ", str1, str2, str = "*";

stringstream ss;

ss.clear();

ss << width;

ss >> str1;

ss.clear();

ss << height;

ss >> str2;

putText(img, strHint + str1 + str + str2, Point(50, 50), CV_FONT_HERSHEY_TRIPLEX, 0.5, Scalar(255, 255, 255), 1, 8, false);

strHint = "fps : ";

ss.clear();

ss << fps;

ss >> str1;

putText(img, strHint + str1, Point(50, 70), CV_FONT_HERSHEY_TRIPLEX, 0.5, Scalar(255, 255, 255), 1, 8, false);

putText(img, "Number of Effects : 10", Point(50, 90), CV_FONT_HERSHEY_TRIPLEX, 0.5, Scalar(255, 255, 255), 1, 8, false);

putText(img, "video_output.avi can be played in player.", Point(50, 110), CV_FONT_HERSHEY_TRIPLEX, 0.5, Scalar(255, 255, 255), 1, 8, false);

putText(img, "Press Esc to Exit.", Point(50, 130), CV_FONT_HERSHEY_TRIPLEX, 0.5, Scalar(255, 255, 255), 1, 8, false);

putText(img, "11521062 ZhaoLei.", Point(width / 2 - 150, height - 50), FONT_HERSHEY_SCRIPT_COMPLEX, 1, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 2, 8, false);

}

   

//图像切换效果

void effects(int id, Mat img)

{

Point2f center = Point2f(width / 2, height / 2);

Point2f point = Point2f(0, 0);

Point2f srcTri[3] = { Point2f(0, 0),Point2f(img.cols, 0),Point2f(0, img.rows) }, dstTri[3];

Point tl, rb;

Mat tmpMat, dstImg, blackImg = Mat::zeros(Size(width, height), CV_8UC3);

int x, y;

cout << "Writing Image";

for (int j = 0; j <= INTERVAL; j++)

{

switch (id)

{

case 0:

tmpMat = getRotationMatrix2D(center, 0.0, 1.2 / INTERVAL * (INTERVAL - j));//缩小

warpAffine(img, dstImg, tmpMat, img.size());

break;

case 1:

//仿射变换

x = img.cols / INTERVAL * (INTERVAL - j);

y = img.rows / INTERVAL * (INTERVAL - j);

dstTri[0] = Point2f(width - x, 0);

dstTri[1] = Point2f(x, 0);

dstTri[2] = Point2f(width - x, img.rows - y);

tmpMat = getAffineTransform(srcTri, dstTri);

warpAffine(img, dstImg, tmpMat, img.size());

break;

case 2:

x = img.cols / INTERVAL * (INTERVAL - j);

y = 4 * height * x * (width - x) / (width * width);

dstTri[0] = Point2f(width - x, y);

dstTri[1] = Point2f(x, y);

dstTri[2] = Point2f(x, img.rows - y);

tmpMat = getAffineTransform(srcTri, dstTri);

warpAffine(img, dstImg, tmpMat, img.size());

tmpMat = getRotationMatrix2D(point, 0, 1.2 / INTERVAL * (INTERVAL - j));

warpAffine(dstImg, dstImg, tmpMat, dstImg.size());

break;

case 3:

tmpMat = getRotationMatrix2D(point, 0, 1.2 / INTERVAL * j);

warpAffine(img, dstImg, tmpMat, img.size());

break;

case 4:

tmpMat = getRotationMatrix2D(center, 360 / INTERVAL * j * 2, 1.2 / INTERVAL * j);//旋转加放大

warpAffine(img, dstImg, tmpMat, img.size());

break;

case 5:

addWeighted(img, 1.0 / INTERVAL * (INTERVAL - j), blackImg, 1.0 / INTERVAL * j, 0, dstImg);//图像混合

break;

case 6:

tl = Point((width / 2) / INTERVAL * (INTERVAL - j), (height / 2) / INTERVAL * (INTERVAL - j));

rb = Point((width / 2) / INTERVAL * j + (width / 2), (height / 2) / INTERVAL * j + (height / 2));

tmpMat = img(Rect(tl.x, tl.y, rb.x - tl.x, rb.y - tl.y));//获取ROI区域

//ROI区域填充矩形

rectangle(tmpMat, Point(0, 0), Point(tmpMat.cols, tmpMat.rows), Scalar(0, 0, 0), CV_FILLED);

dstImg = img;

break;

case 7:

tl = Point((width / 2) / INTERVAL * (INTERVAL - j), (height / 2) / INTERVAL * (INTERVAL - j));

rb = Point((width / 2) / INTERVAL * j + (width / 2), (height / 2) / INTERVAL * j + (height / 2));

tmpMat = img(Rect(tl.x, tl.y, rb.x - tl.x, rb.y - tl.y));

circle(tmpMat, Point(tmpMat.cols / 2, tmpMat.rows / 2), tmpMat.cols / 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), CV_FILLED);

dstImg = img;

break;

case 8:

tmpMat = getRotationMatrix2D(point, 0, 1.2 / INTERVAL * (INTERVAL - j));

warpAffine(img, dstImg, tmpMat, img.size());

break;

case 9:

tmpMat = getRotationMatrix2D(center, 0.0, 1.2 / INTERVAL * j);//放大

warpAffine(img, dstImg, tmpMat, img.size());

break;

}

putTextOnImg(dstImg);

writer.write(dstImg);

cout << ".";

}

cout << "\n";

}

   

//绘制片头(八卦)

void drawStarter()

{

Mat dstImg = Mat::zeros(Size(width, height), CV_8UC3);

int r = height / 2 - 80, a = width / 2, b = height / 2, x, y, ya, yb;

int b1 = height / 2 - r / 2, b2 = height / 2 + r / 2;

cout << "Writing Starter";

for (int j = 0; j <= INTERVAL * 4; j++)

{

//绘大圆

x = 2 * r / (INTERVAL * 2) * j + 80;

ya = sqrt(pow(r, 2) - pow(x - a, 2)) + b;

yb = -sqrt(pow(r, 2) - pow(x - a, 2)) + b;

circle(dstImg, Point(x, ya), 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), CV_FILLED);

circle(dstImg, Point(x, yb), 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), CV_FILLED);

//绘半圆上

y = height / 2 - r / (INTERVAL * 3) * j;

x = -sqrt(pow(r / 2, 2) - pow(y - b1, 2)) + a;

circle(dstImg, Point(x, y), 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), CV_FILLED);

//绘半圆下

y = r / (INTERVAL * 3) * j + height / 2;

x = sqrt(pow(r / 2, 2) - pow(y - b2, 2)) + a;

circle(dstImg, Point(x, y), 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), CV_FILLED);

//绘小圆上

x = r / 4 / (INTERVAL * 3) * j + width / 2 - r / 8;

ya = sqrt(pow(r / 8, 2) - pow(x - a, 2)) + b1;

yb = -sqrt(pow(r / 8, 2) - pow(x - a, 2)) + b1;

circle(dstImg, Point(x, ya), 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), CV_FILLED);

circle(dstImg, Point(x, yb), 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), CV_FILLED);

//绘小圆下

x = r / 4 / (INTERVAL * 3) * j + width / 2 - r / 8;

ya = sqrt(pow(r / 8, 2) - pow(x - a, 2)) + b2;

yb = -sqrt(pow(r / 8, 2) - pow(x - a, 2)) + b2;

circle(dstImg, Point(x, ya), 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), CV_FILLED);

circle(dstImg, Point(x, yb), 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), CV_FILLED);

putTextOnImg(dstImg);

writer.write(dstImg);

cout << ".";

}

cout << "\n";

}

   

//wchar2str

string wchar2str(LPCWSTR wstr)

{

int len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);

if (len <= 0)

return string("");

char* dst = new char[len];

if (dst == NULL)

return string("");

WideCharToMultiByte(CP_ACP, 0, wstr, -1, dst, len, NULL, NULL);

dst[len - 1] = 0;

string str(dst);

delete[] dst;

return str;

}

   

//遍历文件夹下的文件

int listFiles(string str)

{

vec.clear();

WIN32_FIND_DATA findData;

HANDLE error;

//str2wstr

wstring widstr = wstring(str.begin(), str.end());

LPWSTR path = (LPWSTR)widstr.c_str();

   

error = FindFirstFile(path, &findData);

if (error == INVALID_HANDLE_VALUE)

{

cout << "Failed to Find Files!" << "\n";

return 1;

}

do

{

string str = wchar2str(findData.cFileName);

vec.push_back(str);

//cout << str << "\n";

} while (FindNextFile(error, &findData));

return 0;

}

   

int main(int argc, char *argv[])

{

if (argv[1] == NULL)

{

cout << "Please run the program by command line.\ne.g.(Need to enter in the executable directory):\nhomework1.exe E:\\input" << "\n\n";

system("pause");

return 1;

}

   

bool selfExit = false;

Mat frame;

string strSplit = "\\", strType = "*.avi", fileName;

string path = argv[1] + strSplit, fileOutput = "video_output.avi";

listFiles(path + strType);

for each (string file in vec)

{

if (file != "video_output.avi")

fileName = file;

}

capture.open(path + fileName);

if (!capture.isOpened())

{

cout << "Failed to Open Video!";

return 1;

}

width = (int)capture.get(CAP_PROP_FRAME_WIDTH);//1280

height = (int)capture.get(CAP_PROP_FRAME_HEIGHT);//720

cout << "w*h:" << width << "*" << height << "\n";

fps = (int)capture.get(CV_CAP_PROP_FPS);//25fps

cout << "fps:" << fps << "\n";

   

writer.open(path + fileOutput, CV_FOURCC('D', 'I', 'V', 'X'), fps, Size(width, height), true);

drawStarter();

int i = 0;

strType = "*.jpg";

listFiles(path + strType);

for each (string fileName in vec)

{

cout << path + fileName << "\n";

Mat img = imread(path + fileName);

Mat dst = Mat::zeros(Size(width, height), CV_8UC3);

resize(img, dst, dst.size());

effects(i++ % 10, dst);

}

cout << "Writing Video Images";

while (1)

{

if (capture.read(frame))

{

putTextOnImg(frame);

writer.write(frame);

cout << ".";

}

else

break;

}

cout << "\n";

   

namedWindow(WINDOWN_NAME);

capture.open(path + fileOutput);

while (1)

{

if (capture.read(frame))

imshow(WINDOWN_NAME, frame);

else

break;

//每帧间隔interval ms,且按esc退出

if (waitKey(1000 / fps) == 27)

{

selfExit = true;

break;

}

}

cout << "All are successful!\n";

if (!selfExit)

waitKey();

return 0;

}

  • 效果

    media文件夹内的内容(其中video_output.avi为最后生成的视频文件):

    片头效果截图:

    切换效果截图(10种中的一个):

    原视频截图:

       

       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值