C++-OpenCV(6)-视频稳态

对于一个出现抖动的视频,我们如何处理它让它不抖动呢?


关键步骤:
 1.计算相邻帧的变换
    获取前一帧图像中的特征点:    goodFeaturesToTrack()
   获得下一帧图像中的特征点位置:calcOpticalFlowPyrLK()
    计算两帧间的变换:                   estimateAffinePartial2D()  dx+dy+旋转角度
    2*3的矩阵  第1列和第2列是旋转和缩放 可以求出旋转角度
    第3列 是X 方向上和y方向上的平移,可以得到dx dy 以及平移的角度 每个平移间的角度都存起来,相邻帧之间的变换。

2.计算相邻帧之间的运行轨迹 
   特征点的运动轨迹:cumsum
                                   帧间的位移和旋转角度累积起来

   视频平滑:smooth;计算方法:  滑动平均 累加/count
                                    滑动窗口大小:radius
   重新计算:transforms_smooth=smoothed_trajectory-trajectory
3. wapAffine 重新生成下一帧图像
代码如下:
 

//输入视频序列帧
	VideoCapture cap(0);
	int n_frames = int(cap.get(CAP_PROP_FRAME_COUNT));//宽高和频率
	int w = int(cap.get(CAP_PROP_FRAME_WIDTH));
	int h = int(cap.get(CAP_PROP_FRAME_HEIGHT));
	double fps = cap.get(CAP_PROP_FPS);

	//输出视频
	string outfile = "video_out.avi";
	VideoWriter out("video_out.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'), fps, Size(2 * w, h));

	//前一帧和下一帧,且为灰度图
	Mat curr, curr_gray;
	Mat prev, prev_gray;
	cap >> prev;
	cvtColor(prev, prev_gray, COLOR_BGR2GRAY);


	//1.寻找特征点并计算相邻帧的变换 相邻帧
	vector <TransformParam> transforms;
	Mat last_T;
	for (int i = 1; i < n_frames - 1; i++)
	{
	    //前一帧的点和当前帧的点
		vector <Point2f> prev_pts, curr_pts;
		//特征点在前一帧的位置 
		goodFeaturesToTrack(prev_gray, prev_pts, 200, 0.01, 30);
		//读取当前帧
		bool success = cap.read(curr);
		if (!success) break;
		cvtColor(curr, curr_gray, COLOR_BGR2GRAY);
		vector <uchar> status;
		vector <float> err;
		//输入前一帧、当前帧、特征点
		calcOpticalFlowPyrLK(prev_gray, curr_gray, prev_pts, curr_pts, status, err);
		// 过滤点
		auto prev_it = prev_pts.begin();
		auto curr_it = curr_pts.begin();
		for (size_t k = 0; k < status.size(); k++)
		{
			if (status[k])
			{
				prev_it++;
				curr_it++;
			}
			else
			{
				prev_it = prev_pts.erase(prev_it);
				curr_it = curr_pts.erase(curr_it);
			}
		}
		// 计算两帧之间的变化 dx+dy+旋转角度
		Mat T = estimateAffinePartial2D(prev_pts, curr_pts);
		if (T.data == NULL) last_T.copyTo(T);
		T.copyTo(last_T);
		// x y的偏移量 第3列
		double dx = T.at<double>(0, 2);
		double dy = T.at<double>(1, 2);
		//根据第0 1列求 旋转角度 Extract rotation angle
		double da = atan2(T.at<double>(1, 0), T.at<double>(0, 0));
		// Store transformation 
		transforms.push_back(TransformParam(dx, dy, da));
		// Move to next frame
		curr_gray.copyTo(prev_gray);
		cout << "Frame: " << i << "/" << n_frames << " -  Tracked points : " << prev_pts.size() << endl;
	}

	// 2.计算运动轨迹:存的transforms_smooth=平滑后(trajectory)-平滑前(trajectory)

	vector <Trajectory> trajectory = cumsum(transforms);
	vector <Trajectory> smoothed_trajectory = smooth(trajectory, SMOOTHING_RADIUS);
	vector <TransformParam> transforms_smooth;
	for (size_t i = 0; i < transforms.size(); i++)
	{
		// 
		double diff_x = smoothed_trajectory[i].x - trajectory[i].x;
		double diff_y = smoothed_trajectory[i].y - trajectory[i].y;
		double diff_a = smoothed_trajectory[i].a - trajectory[i].a;

		// Calculate newer transformation array
		double dx = transforms[i].dx + diff_x;
		double dy = transforms[i].dy + diff_y;
		double da = transforms[i].da + diff_a;

		transforms_smooth.push_back(TransformParam(dx, dy, da));
	}

	//3.生成新的图像
	cap.set(CAP_PROP_POS_FRAMES, 0);
	Mat T(2, 3, CV_64F);
	Mat frame, frame_stabilized, frame_out;

	for (int i = 0; i < n_frames - 1; i++)
	{
		bool success = cap.read(frame);
		if (!success) break;

		// Extract transform from translation and rotation angle. 
		transforms_smooth[i].getTransform(T);

		// Apply affine wrapping to the given frame
		warpAffine(frame, frame_stabilized, T, frame.size());

		// Scale image to remove black border artifact
		fixBorder(frame_stabilized);

		// Now draw the original and stablised side by side for coolness
		hconcat(frame, frame_stabilized, frame_out);

		// If the image is too big, resize it.
		if (frame_out.cols > 1920)
		{
			resize(frame_out, frame_out, Size(frame_out.cols / 2, frame_out.rows / 2));
		}

		//imshow("Before and After", frame_out);
		out.write(frame_out);
		//waitKey(10);
	}

	// Release video
	cap.release();
	out.release();

 

posted @ 2021-03-10 22:16  jasmineTang  阅读(309)  评论(1)    收藏  举报