OpenCV C++案例实战十八《抖音特效——“蓝线挑战”》

OpenCV C++案例实战十八《抖音特效——“蓝线挑战”》


前言

本文将使用OpenCV C++ 实现抖音上的特效“蓝线挑战”。虽然看起来觉得很牛的样子,但如果了解其中的原理就非常简单了。本案例是我自己对于这个特效实现过程的理解,仅供参考。
算法原理可以分为三个流程:
1、将视频(图像)从(顶->底)或(左->右)逐行(列)扫描图像。
2、将扫描完成的行(列)像素重新生成定格图像。
3、使用原帧图像像素填充未扫描到的像素。
接下来就具体来看看是如何实现的吧。

一、图像扫描

首先第一步,拿到一个视频(很多帧图像)可以简单的看成图像处理。我们需要将图像从顶到底逐行进行像素扫描,当然也可以从左到右逐列扫描,这要看你想要实现什么样的效果。在这里,我实现的是从上到下逐行扫描。效果如图所示。

请添加图片描述

二、生成定格图像

所谓生成定格图像就是将我们每扫描到的行像素重新进行绘制。

	//从顶向下逐行扫描图像
	if (h < height)
	{
		h++;
		//将扫描到的图像像素进行重新绘制,生成新图像
		for (int j = 0; j < width; j++)
		{
			for (int c = 0; c < 3; c++)
			{
				temp.at<Vec3b>(h, j)[c] = canvas.at<Vec3b>(h, j)[c];
			}
		}
		//绘制扫描过程
		line(canvas, Point(0, h), Point(width, h), Scalar(255, 255, 0), 2);
	}

 
 

    请添加图片描述
    如图所示,这是使用上面代码段实现的逐行扫描生成定格图像。从效果上看,已经得到了我们想要的大致效果了。不过现在的问题是,经扫描到的行有像素填充,未扫描到的行还是漆黑一片。所以接下来我们需要做的就是将未扫描到的行用原图进行填充。具体请看源码注释。

    三、图像混合

    //将两幅图像进行线性混合
    bool Linear_Blend(Mat src1, Mat src2, Mat& dst)
    {
    	/*
    	参数说明:
    	src1:生成的定格图像。由于生成的定格图像是从顶往下逐行扫描,故在扫描线下的像素为0
    	src2:原视频帧图像
    	dst:新生成的定格图像。
    	算法原理:经扫描到的像素用src1进行填充,未扫描到的像素用src2进行填充,这样就可以得到我们所要的效果了。
    	*/
    

    for (int i = 0; i < src1.rows; i++)
    {
    for (int j = 0; j < src1.cols; j++)
    {
    for (int c = 0; c < 3; c++)
    {
    if (src1.at<Vec3b>(i, j)[0] != 0)
    {
    dst.at<Vec3b>(i, j)[c] = src1.at<Vec3b>(i, j)[c];
    }
    else
    {
    dst.at<Vec3b>(i, j)[c] = src2.at<Vec3b>(i, j)[c];
    }
    }
    }
    }

    return true;
    }

      四、效果显示

      请添加图片描述
      如上图所示,至此我们已经完成了案例所想要的效果。请参考源码,注释也比较详细了。

      五、源码

      #include<iostream>
      #include<opencv2/opencv.hpp>
      using namespace std;
      using namespace cv;
      

      /*
      抖音特效:蓝线挑战
      算法原理:
      1、将视频(图像)从(顶->底)或(左->右)逐行(列)扫描图像。
      2、将扫描完成的行(列)像素重新生成定格图像
      3、使用原帧图像像素填充未扫描到的像素
      */

      //将两幅图像进行线性混合
      bool Linear_Blend(Mat src1, Mat src2, Mat& dst)
      {
      /*
      参数说明:
      src1:生成的定格图像。由于生成的定格图像是从顶往下逐行扫描,故在扫描线下的像素为0
      src2:原视频帧图像
      dst:新生成的定格图像。
      算法原理:经扫描到的像素用src1进行填充,未扫描到的像素用src2进行填充,这样就可以得到我们所要的效果了。
      */

      for (int i = 0; i < src1.rows; i++)
      {
      for (int j = 0; j < src1.cols; j++)
      {
      for (int c = 0; c < 3; c++)
      {
      if (src1.at<Vec3b>(i, j)[0] != 0)
      {
      dst.at<Vec3b>(i, j)[c] = src1.at<Vec3b>(i, j)[c];
      }
      else
      {
      dst.at<Vec3b>(i, j)[c] = src2.at<Vec3b>(i, j)[c];
      }
      }
      }
      }

      return true;
      }

      int main()
      {
      VideoCapture capture;
      capture.open(“test.avi”);
      if (!capture.isOpened())
      {
      cout << “can not open the camera!” << endl;
      system(“pause”);
      return -1;
      }

      int width = capture.get(CAP_PROP_FRAME_WIDTH);//视频帧宽
      int height = capture.get(CAP_PROP_FRAME_HEIGHT);//视频帧高

      //保存视频
      VideoWriter writer;
      int fourcc = writer.fourcc(‘m’, ‘p’, ‘4’, ‘v’); //视频编码
      Size size(capture.get(CAP_PROP_FRAME_WIDTH), capture.get(CAP_PROP_FRAME_HEIGHT));
      writer.open(“result.avi”, fourcc, 30, size, true);

      int h = 0;//定义变量,代表当前扫描高度

      //用于生成定格照
      Mat temp = Mat::zeros(Size(width, height), CV_8UC3);

      Mat frame;
      while (capture.read(frame))
      {
      //将图像拷贝一份,用于每帧更新
      Mat canvas = frame.clone();

      //从顶向下逐行扫描图像
      if (h < height)
      {
      h++;
      //将扫描到的图像像素进行重新绘制,生成新图像
      for (int j = 0; j < width; j++)
      {
      for (int c = 0; c < 3; c++)
      {
      temp.at<Vec3b>(h, j)[c] = canvas.at<Vec3b>(h, j)[c];
      }
      }
      //绘制扫描过程
      line(canvas, Point(0, h), Point(width, h), Scalar(255, 255, 0), 2);
      }

      Mat result = Mat::zeros(frame.size(), frame.type());//蓝线挑战最终定格图
      Linear_Blend(temp, canvas, result); //将两张图像进行像素叠加

      //writer.write(temp);//进行视频保存

      imshow(“定格图像”, temp);
      imshow(“原视频帧”, canvas);
      imshow(“蓝线挑战”, result);

      char key = waitKey(10);
      if (key == 27) break;
      }

      capture.release();
      system(“pause”);
      return 0;
      }


        总结

        本文使用OpenCV C++ 实现抖音特效“蓝线挑战”,关键步骤有以下几点。
        1、将图像进行逐行扫描
        2、将扫描到的像素逐行生成定格图像
        3、将定格图像与原图像进行像素叠加。

        • 0
          点赞
        • 0
          收藏
          觉得还不错? 一键收藏
        • 0
          评论
        评论
        添加红包

        请填写红包祝福语或标题

        红包个数最小为10个

        红包金额最低5元

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

        抵扣说明:

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

        余额充值