1、在视频中插入Logo
#include <iostream>
#include <opencv2/opencv.hpp>
#include <Windows.h>
#include <vector>
using namespace std;
void make_video(vector<cv::Mat> res) {
cout << "几张:"<<res.size();
cv::VideoWriter writer;
bool isColor = true;
int frame_fps = 25;
int frame_width = 352;
int frame_height = 288;
string video_name = "res.avi";
cv::Mat mine = cv::imread("F:\\post_study\\Second_year\\多媒体\\item1\\2.png");
cv::Mat mine2;
cv::resize(mine, mine2, cv::Size(res[0].cols/3, res[0].rows/2), (0, 0), (0, 0), 3);
cv::Mat roi_img = res[0](cv::Rect(130, 64, mine2.cols, mine2.rows));
cv::Mat dstImage;
cv::addWeighted(mine2, 0.5, roi_img, 0.5, 0.0, dstImage);
dstImage.copyTo(roi_img);
writer = cv::VideoWriter(video_name, CV_FOURCC('M', 'J', 'P', 'G'), frame_fps, cv::Size(frame_width, frame_height), isColor);
//写入
for (int i = 0; i < 25; i++) {
writer.write(res[0]);
}
for (int i = 1; i < res.size(); i++) {
writer.write(res[i]);
}
}
int main2()
{
const char *s_path = "F:\\post_study\\Second_year\\多媒体\\item1\\funfair.cif";
const int img_w = 352;
const int img_h = 288;
FILE* pFileIn = fopen(s_path, "rb");
int bufLen = img_w * img_h * 3 / 2;
unsigned char* pYuvBuf = new unsigned char[bufLen];
int iCount = 0;
cv::Mat logo_img2 = cv::imread("F:\\post_study\\Second_year\\多媒体\\item1\\logo.jpg");
cv::Mat logo_img;
cv::resize(logo_img2, logo_img, cv::Size(logo_img2.cols / 12, logo_img2.rows / 12), (0, 0), (0, 0), 3);
vector<cv::Mat> imgs;
for (iCount = 0; iCount < 250; iCount++) {
cv::Mat rgbImg;
cv::Mat yuvImg;
yuvImg.create(img_h * 3 / 2, img_w, CV_8UC1);
fread(pYuvBuf, bufLen * sizeof(unsigned char), 1, pFileIn);
memcpy(yuvImg.data, pYuvBuf, bufLen * sizeof(unsigned char));
cv::cvtColor(yuvImg, rgbImg, CV_YUV2BGR_I420);
if (iCount == 0) {
imgs.push_back(rgbImg);
}
else {
double alphaValue = 0.3;
alphaValue = 1 - (double)iCount / 250;
double betaValue = 1 - alphaValue;
cv::Mat roi_img = rgbImg(cv::Rect(0, 0, logo_img.cols, logo_img.rows));
cv::Mat dstImage;
cv::addWeighted(logo_img, alphaValue, roi_img, betaValue, 0.0, dstImage);
dstImage.copyTo(roi_img);
cv::imshow("img", rgbImg);
cv::waitKey(1);
printf("%d \n", iCount);
imgs.push_back(rgbImg);
Sleep(5);
}
}
make_video(imgs);
delete[] pYuvBuf;
fclose(pFileIn);
}
2、建立哈夫曼编码
#include <iostream>
using namespace std;
#include <vector>
#include <string>
#include <cstdlib>
#include<math.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <ctype.h>
#define MAX 999999 //一个极大值
#define NUM 10
//存储哈夫曼树每个结点
typedef struct Node {
char ch;
int weight; //权值
int parent;
int lchild, rchild;
}HFNode;
//存储每个字符及其哈夫曼编码
typedef struct {
char ch;
char code[NUM];
}HFCharCode;
HFNode HT[28 * 2 - 1]; //哈夫曼树结构体
HFCharCode HCD[28]; //哈夫曼编码结构体
int LeafNum; //叶子结点数
int NodeNum; //所有结点数
char EnterStr[MAX]; //输入的待编码电文
char EnterCode[MAX]; //输入的待解码密文
char RealStr[MAX]; //密文解码后的电文
int AllWeight[28]; //存储所有28个字符的权值
void Statistics();
void CreateHFTree();
void SelectMin(int &min1, int &min2);
void CreateHFCode();
void ReverseStr(char *str);
void EncodeStr();
void DecodeHFCode();
//统计每个字符权值
void Statistics() {
int len = strlen(EnterStr);
for (int i = 0; i <= 27; i++)
AllWeight[i] = 0;
for (int j = 0; j <= len - 1; j++) {
if (isalpha(EnterStr[j])) {
EnterStr[j] = tolower(EnterStr[j]);
AllWeight[EnterStr[j] - 'a']++;
}
else if ((int)EnterStr[j] == 44)
AllWeight[26]++;
else if ((int)EnterStr[j] == 46)
AllWeight[27]++;
else {
printf("\n输入不符合要求!\n\n");
exit(-1);
}
}
int i = 0, j = 0;
for (; i <= 25; i++) {
if (AllWeight[i] != 0) {
HT[j].weight = AllWeight[i];
HT[j].ch = i + 'a';
j++;
}
}
if (AllWeight[i] != 0) {
HT[j].weight = AllWeight[i];
HT[j].ch = ',';
j++;
i++;
}
if (AllWeight[i] != 0) {
HT[j].weight = AllWeight[i];
HT[j].ch = '.';
}
printf("\n*** 打印每个字符的权值 ***\n");
int n = 0;
for (int i = 0; i <= 27; i++) {
if (AllWeight[i] != 0) {
n++;
if (i <= 25)
putchar('a' + i);
else if (i == 26)
printf(",");
else
printf(".");
printf(": %d\n", AllWeight[i]);
}
}
LeafNum = n;
NodeNum = 2 * LeafNum - 1;
}
//构造哈夫曼树
void CreateHFTree() {
int i;
for (i = 0; i <= LeafNum - 1; i++) {
HT[i].parent = -1;
HT[i].lchild = -1;
HT[i].rchild = -1;
HT[i].weight = HT[i].weight;
}
for (; i <= NodeNum - 1; i++) {
HT[i].parent = -1;
HT[i].lchild = -1;
HT[i].rchild = -1;
HT[i].weight = MAX;
}
int min1, min2;
for (i = LeafNum; i <= NodeNum - 1; i++) {
SelectMin(min1, min2);
HT[min1].parent = i;
HT[min2].parent = i;
HT[i].lchild = min1;
HT[i].rchild = min2;
HT[i].weight = HT[min1].weight + HT[min2].weight;
}
// printf("\n*** 打印哈夫曼树 ***\n");
// for(int i = 0; i <= NodeNum-1; i++) {
// printf("序号:%d 字符:%c 权值:%d 双亲:%d 左孩:%d 右孩:%d\n", i, HT[i].ch, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
// }
}
//找到两个权值最小的二叉树的序号
void SelectMin(int &min1, int &min2) {
int i = 0;
int temp;
int wetmin1, wetmin2;
while (HT[i].parent != -1)
i++;
wetmin1 = HT[i].weight;
min1 = i;
i++;
while (HT[i].parent != -1)
i++;
wetmin2 = HT[i].weight;
min2 = i;
i++;
if (wetmin1 > wetmin2) {
temp = wetmin2;
wetmin2 = wetmin1;
wetmin1 = temp;
temp = min2;
min2 = min1;
min1 = temp;
}
for (; i <= NodeNum - 1; i++) {
if (HT[i].weight < wetmin1 && HT[i].parent == -1) {
wetmin2 = wetmin1;
wetmin1 = HT[i].weight;
min2 = min1;
min1 = i;
}
else if (HT[i].weight < wetmin2 && HT[i].parent == -1) {
wetmin2 = HT[i].weight;
min2 = i;
}
}
}
//进行哈夫曼编码
void CreateHFCode() {
int i, j, len;
for (i = 0; i <= LeafNum - 1; i++) {
len = 0;
j = i;
HCD[i].ch = HT[j].ch;
while (HT[j].parent != -1) { //不是根节点
if (HT[HT[j].parent].lchild == j) { //是双亲结点的左孩子
HCD[i].code[len++] = '0' + 0; //加上字符0
}
else //是右孩子
HCD[i].code[len++] = '0' + 1; //加上字符1
j = HT[j].parent; //往上遍历
}
HCD[i].code[len] = '\0'; //字符串末尾
ReverseStr(HCD[i].code);
}
printf("\n*** 打印每个字符的编码 ***\n");
for (int i = 0; i <= LeafNum - 1; i++)
printf("%c: %s\n", HT[i].ch, HCD[i].code);
}
//将一个字符串反转
void ReverseStr(char *str) {
int i, j;
char c;
for (i = 0, j = strlen(str) - 1; i < j; i++, j--) {
c = str[i];
str[i] = str[j];
str[j] = c;
}
}
//哈夫曼编码
void EncodeStr() {
int len = strlen(EnterStr);
printf("\n*** 编码结果 ***\n");
for (int i = 0; i <= 20; i++) {
for (int j = 0; j <= LeafNum - 1; j++) {
if (EnterStr[i] == HCD[j].ch)
printf("%s", HCD[j].code);
}
}
cout << "..." << endl;
printf("\n");
}
//哈夫曼解码
void DecodeHFCode() {
int k = NodeNum - 1; //根结点序号, 开始时一定在最后一个
int len = 0, i = 0;
while (EnterCode[i]) {
if (EnterCode[i] == '0' + 0)
k = HT[k].lchild;
else if (EnterCode[i] == '0' + 1)
k = HT[k].rchild;
else {
printf("\n错误! 密文中仅能含有1和0!\n\n");
exit(-1);
}
if (HT[k].lchild == -1 && HT[k].rchild == -1) {
RealStr[len++] = HT[k].ch;
k = NodeNum - 1;
}
i++;
}
RealStr[len] = '\0';
if (k == NodeNum - 1) {
printf("\n*** 解码结果 ***\n%s\n\n", RealStr);
exit(0);
}
printf("\n错误! 部分密文无法解密!\n\n");
exit(-1);
}
int main3() {
vector <long> get_nums = { 500,1000,5000,10000,20000,30000,50000,100000 };
vector <char> wait_code = { 'a','b','c','d','e','f','g','h' };
for (auto i : get_nums) {
cout << "该次的测试长度为:" << " " << i<<endl;
string temp = "";
vector<int> tmp;
for (int j = 1; j <= i; j++) {
tmp.push_back(rand() % 100 +1);
}
for (int j = 0; j < tmp.size(); j++) {
if (tmp[j] >= 1 & tmp[j] <= 31) temp += 'a';
else if (tmp[j] >= 32 & tmp[j] <= 43) temp += 'b';
else if (tmp[j] >= 44 & tmp[j] <= 49) temp += 'c';
else if (tmp[j] >= 50 & tmp[j] <= 69) temp += 'd';
else if (tmp[j] >= 70 & tmp[j] <= 70) temp += 'e';
else if (tmp[j] >= 71 & tmp[j] <= 88) temp += 'f';
else if (tmp[j] >= 89 & tmp[j] <= 90) temp += 'g';
else temp += 'h';
}
tmp.clear();
for (int k = 0; k <= 40; k++) cout << temp[k];
cout << "..." << endl;
double a_num = 0;
double b_num = 0;
double c_num = 0;
double d_num = 0;
double e_num = 0;
double f_num = 0;
double g_num = 0;
double h_num = 0;
for (int k = 0; k < temp.size(); k++) {
if (temp[k] == 'a') a_num++;
else if (temp[k] == 'b') b_num++;
else if (temp[k] == 'c') c_num++;
else if (temp[k] == 'd') d_num++;
else if (temp[k] == 'e') e_num++;
else if (temp[k] == 'f') f_num++;
else if (temp[k] == 'g') g_num++;
else h_num++;
}
vector <double> p_seq;
p_seq.push_back((double)(a_num / i));
p_seq.push_back((double)(b_num / i));
p_seq.push_back((double)(c_num / i));
p_seq.push_back((double)(d_num / i));
p_seq.push_back((double)(e_num / i));
p_seq.push_back((double)(f_num / i));
p_seq.push_back((double)(g_num / i));
p_seq.push_back((double)(h_num / i));
for (int k = 0; k < p_seq.size(); k++) {
cout << p_seq[k] << " ";
}
cout << endl;
double entropy = 0;
for (int k = 0; k < p_seq.size(); k++) {
; entropy += -p_seq[k] * (log(p_seq[k]));
}
cout << "熵值为:" << entropy << endl;
for (int k = 0; k < temp.size(); k++) EnterStr[k] = temp[k];
//EnterStr[temp.size()] = '\r';
Statistics();
CreateHFTree();
CreateHFCode();
EncodeStr();
string s_temp = "";
/*while (1) {
for (int z = 1; z <= 31; z++) s_temp += 'a';
for (int z = 1; z <= 12; z++) s_temp += 'b';
for (int z = 1; z <= 6; z++) s_temp += 'c';
for (int z = 1; z <= 20; z++) s_temp += 'd';
for (int z = 1; z <= 1; z++) s_temp += 'e';
for (int z = 1; z <= 18; z++) s_temp += 'f';
for (int z = 1; z <= 2; z++) s_temp += 'g';
for (int z = 1; z <= 10; z++) s_temp += 'h';
break;
}
set(s_temp);
for (int i = 0; i<num; i++) {
cout << sign[i] << " " << rate[i] << endl;
}
find(temp);
cout << temp;*/
int len = strlen(EnterStr);
printf("\n*** 编码结果 ***\n");
long huff_len = 0;
for (int i = 0; i <= len; i++) {
for (int j = 0; j <= LeafNum - 1; j++) {
if (EnterStr[i] == HCD[j].ch)
huff_len+= strlen(HCD[j].code);
}
}
cout << "哈夫曼平均编码长度为:" << (double)huff_len / i;
cout << endl;
}
system("pause");
return 0;
}
3、具体运动补偿和运动估计的代码:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <opencv2/opencv.hpp>
#include <ctime>
using namespace std;
using namespace cv;
// 描述:声明全局函数
void tracking(Mat &frame, Mat &output);
bool addNewPoints();
bool acceptTrackedPoint(int i);
// 描述:声明全局变量
string window_name = "optical flow tracking";
Mat gray; // 当前图片
Mat gray_prev; // 预测图片
vector<Point2f> points[2]; // point0为特征点的原来位置,point1为特征点的新位置
vector<Point2f> initial; // 初始化跟踪点的位置
vector<Point2f> features; // 检测的特征
int maxCount = 500; // 检测的最大特征数
double qLevel = 0.01; // 特征检测的等级
double minDist = 10.0; // 两特征点之间的最小距离
vector<uchar> status; // 跟踪特征的状态,特征的流发现为1,否则为0
vector<float> err;
//输入格式是Mat类型,I1,I2代表是输入的两幅图像
double getPSNR(const Mat& I1, const Mat& I2)
{
Mat s1;
absdiff(I1, I2, s1); // |I1 - I2|AbsDiff函数是 OpenCV 中计算两个数组差的绝对值的函数
s1.convertTo(s1, CV_32F); // 这里我们使用的CV_32F来计算,因为8位无符号char是不能进行平方计算
s1 = s1.mul(s1); // |I1 - I2|^2
Scalar s = sum(s1); //对每一个通道进行加和
double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
if (sse <= 1e-10) // 对于非常小的值我们将约等于0
return 0;
else
{
double mse = sse / (double)(I1.channels() * I1.total());//计算MSE
double psnr = 10.0*log10((255 * 255) / mse) / 2;
return psnr;//返回PSNR
}
}
int main()
{
const char *s_path = "F:/post_study/Second_year/多媒体/item1/funfair.cif";
ofstream outfile;
string outputFile = "F:/post_study/Second_year/多媒体/item1/out.txt";
outfile.open(outputFile, ostream::app); /*以添加模式打开文件*/
const int img_w = 352;
const int img_h = 288;
const int bufLen = img_w * img_h * 3 / 2;
FILE* pFileIn = fopen(s_path, "rb");
unsigned char* pYuvBuf = new unsigned char[bufLen];
for (int iCount = 0; iCount < 250; iCount++) {
cv::Mat rgbImg;
cv::Mat yuvImg;
yuvImg.create(img_h * 3 / 2, img_w, CV_8UC1);
fread(pYuvBuf, bufLen * sizeof(unsigned char), 1, pFileIn);
memcpy(yuvImg.data, pYuvBuf, bufLen * sizeof(unsigned char));
cv::cvtColor(yuvImg, rgbImg, CV_YUV2BGR_I420); // YUV转RGB
// 开始计时
clock_t start = clock();
// 先进行运动估计
//Mat result, afterMotion;
//cvtColor(DCTU, DCTUforRGB, CV_YUV2BGR_I420);
//tracking(DCTUforRGB, result);
// 分解为YUV颜色空间
Mat YUVImage;
cvtColor(rgbImg, YUVImage, CV_BGR2YUV);
// 分解为三个通道
vector<Mat> YUV;
split(YUVImage, YUV);
//imshow("Y 分量", YUV[0]);
//imshow("U 分量", YUV[1]);
//imshow("V 分量", YUV[2]);
// 先转换下格式
Mat float_Y, float_U, float_V;
YUV[0].convertTo(float_Y, CV_64FC1);
YUV[1].convertTo(float_U, CV_64FC1);
YUV[2].convertTo(float_V, CV_64FC1);
// 基于8*8块的DCT变换及其反变换
Rect windows; //利用这个8*8的矩形来进行8*8块的DCT变换
// DCT变换
Mat DCTU, DCTV, DCTY;
float_Y.copyTo(DCTY);
float_U.copyTo(DCTU);
float_V.copyTo(DCTV);
for (int i = 0;i < img_w / 8;i++)
{
for (int j = 0;j < img_h / 8;j++)
{
windows.x = 8 * i;
windows.y = 8 * j;
windows.height = 8;
windows.width = 8;
dct(float_Y(windows), DCTY(windows));
dct(float_U(windows), DCTU(windows));
dct(float_V(windows), DCTV(windows));
}
}
imshow("DCT_Y", DCTY);
imshow("DCT_U", DCTU);
imshow("DCT_V", DCTV);
// 编码
vector<unsigned char> DCTY_code;
vector<unsigned char> DCTU_code;
vector<unsigned char> DCTV_code;
imencode(".jpg", DCTY, DCTY_code);
imencode(".jpg", DCTU, DCTU_code);
imencode(".jpg", DCTV, DCTV_code);
// 解码
Mat DCTY_decode = imdecode(DCTY_code, CV_LOAD_IMAGE_COLOR);
Mat DCTU_decode = imdecode(DCTU_code, CV_LOAD_IMAGE_COLOR);
Mat DCTV_decode = imdecode(DCTV_code, CV_LOAD_IMAGE_COLOR);
// 逆DCT变换
for (int i = 0;i < img_w / 8;i++)
{
for (int j = 0;j < img_h / 8;j++)
{
windows.x = 8 * i;
windows.y = 8 * j;
windows.height = 8;
windows.width = 8;
dct(DCTY(windows), float_Y(windows), DCT_INVERSE);
dct(DCTU(windows), float_U(windows), DCT_INVERSE);
dct(DCTV(windows), float_V(windows), DCT_INVERSE);
}
}
vector<Mat> YUV_dst(3);
// 格式转换
float_Y.convertTo(YUV_dst[0], CV_8UC1);
float_U.convertTo(YUV_dst[1], CV_8UC1);
float_V.convertTo(YUV_dst[2], CV_8UC1);
//imshow("IDCT_Y", YUV_dst[0]);
//imshow("IDCT_U", YUV_dst[1]);
//imshow("IDCT_V", YUV_dst[2]);
// 将三个通道进行合并
Mat yuv, dst_RGB;
merge(YUV_dst, yuv);
// 转为RGB图像
cvtColor(yuv, dst_RGB, CV_YUV2BGR);
// 结束计时
clock_t end = clock();
// 计算速率
double timeInterval = (double)(end - start) / CLOCKS_PER_SEC;
double rate = 1 / timeInterval;
//cout << "rate : " << rate << "\t";
// 计算psnr
double psnr = getPSNR(rgbImg, dst_RGB);
cout << "PSNR : " << psnr << endl;
// 将速率和psnr输出到txt供python调用
outfile << rate << " " << psnr << " ";
//imshow("Y", YUV_dst[0]);
//imshow("U", YUV_dst[1]);
//imshow("V", YUV_dst[2]);
//imshow("YUV", yuv);
//imshow("src", rgbImg);
//imshow("dst", dst_RGB);
waitKey(40);
}
delete[] pYuvBuf;
fclose(pFileIn);
}
// parameter: frame 输入的视频帧
// output 有跟踪结果的视频帧
void tracking(Mat &frame, Mat &output)
{
cvtColor(frame, gray, CV_BGR2GRAY);
frame.copyTo(output);
// 添加特征点
if (addNewPoints())
{
goodFeaturesToTrack(gray, features, maxCount, qLevel, minDist);
points[0].insert(points[0].end(), features.begin(), features.end());
initial.insert(initial.end(), features.begin(), features.end());
}
if (gray_prev.empty())
{
gray.copyTo(gray_prev);
}
// l-k光流法运动估计
calcOpticalFlowPyrLK(gray_prev, gray, points[0], points[1], status, err);
// 去掉一些不好的特征点
int k = 0;
for (size_t i = 0; i < points[1].size(); i++)
{
if (acceptTrackedPoint(i))
{
initial[k] = initial[i];
points[1][k++] = points[1][i];
}
}
points[1].resize(k);
initial.resize(k);
// 显示特征点和运动轨迹
for (size_t i = 0; i < points[1].size(); i++)
{
line(output, initial[i], points[1][i], Scalar(0, 0, 255));
circle(output, points[1][i], 3, Scalar(0, 255, 0), -1);
}
// 把当前跟踪结果作为下一此参考
swap(points[1], points[0]);
swap(gray_prev, gray);
imshow(window_name, output);
}
// 检测新点是否应该被添加
// return: 是否被添加标志
bool addNewPoints()
{
return points[0].size() <= 10;
}
//决定哪些跟踪点被接受
bool acceptTrackedPoint(int i)
{
return status[i] && ((abs(points[0][i].x - points[1][i].x) + abs(points[0][i].y - points[1][i].y)) > 2);
}