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
//存儲哈夫曼樹每個結(jié)點
typedef struct Node {
char ch;
int weight; //權(quán)值
int parent;
int lchild, rchild;
}HFNode;
//存儲每個字符及其哈夫曼編碼
typedef struct {
char ch;
char code[NUM];
}HFCharCode;
HFNode HT[28 * 2 - 1]; //哈夫曼樹結(jié)構(gòu)體
HFCharCode HCD[28]; //哈夫曼編碼結(jié)構(gòu)體
int LeafNum; //葉子結(jié)點數(shù)
int NodeNum; //所有結(jié)點數(shù)
char EnterStr[MAX]; //輸入的待編碼電文
char EnterCode[MAX]; //輸入的待解碼密文
char RealStr[MAX]; //密文解碼后的電文
int AllWeight[28]; //存儲所有28個字符的權(quán)值
void Statistics();
void CreateHFTree();
void SelectMin(int &min1, int &min2);
void CreateHFCode();
void ReverseStr(char *str);
void EncodeStr();
void DecodeHFCode();
//統(tǒng)計每個字符權(quán)值
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*** 打印每個字符的權(quá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;
}
//構(gòu)造哈夫曼樹
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 權(quán)值:%d 雙親:%d 左孩:%d 右孩:%d\n", i, HT[i].ch, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
// }
}
//找到兩個權(quán)值最小的二叉樹的序號
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) { //不是根節(jié)點
if (HT[HT[j].parent].lchild == j) { //是雙親結(jié)點的左孩子
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);
}
//將一個字符串反轉(zhuǎn)
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*** 編碼結(jié)果 ***\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; //根結(jié)點序號, 開始時一定在最后一個
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*** 解碼結(jié)果 ***\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*** 編碼結(jié)果 ***\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;
// 描述:聲明全局函數(shù)
void tracking(Mat &frame, Mat &output);
bool addNewPoints();
bool acceptTrackedPoint(int i);
// 描述:聲明全局變量
string window_name = "optical flow tracking";
Mat gray; // 當前圖片
Mat gray_prev; // 預(yù)測圖片
vector<Point2f> points[2]; // point0為特征點的原來位置狭瞎,point1為特征點的新位置
vector<Point2f> initial; // 初始化跟蹤點的位置
vector<Point2f> features; // 檢測的特征
int maxCount = 500; // 檢測的最大特征數(shù)
double qLevel = 0.01; // 特征檢測的等級
double minDist = 10.0; // 兩特征點之間的最小距離
vector<uchar> status; // 跟蹤特征的狀態(tài)细移,特征的流發(fā)現(xiàn)為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函數(shù)是 OpenCV 中計算兩個數(shù)組差的絕對值的函數(shù)
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轉(zhuǎn)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]);
// 先轉(zhuǎn)換下格式
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);
// 格式轉(zhuǎn)換
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);
// 轉(zhuǎn)為RGB圖像
cvtColor(yuv, dst_RGB, CV_YUV2BGR);
// 結(jié)束計時
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調(diào)用
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 有跟蹤結(jié)果的視頻幀
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);
}
// 把當前跟蹤結(jié)果作為下一此參考
swap(points[1], points[0]);
swap(gray_prev, gray);
imshow(window_name, output);
}
// 檢測新點是否應(yīng)該被添加
// 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);
}