C++ OpenCV实现抖音"蓝线挑战"特效

目录
  • 前言
  • 一、图像扫描
  • 二、生成定格图像
  • 三、图像混合
  • 四、效果显示
  • 五、源码
  • 总结

前言

本文将使用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、将定格图像与原图像进行像素叠加。

以上就是C++ OpenCV实现抖音"蓝线挑战"特效的详细内容,更多关于C++ OpenCV蓝线挑战特效的资料请关注我们其它相关文章!

(0)

相关推荐

  • C++ OpenCV实现二维码检测功能

    目录 前言 一.二维码检测 二.二维码识别 三.二维码绘制 四.源码 总结 前言 本文将使用OpenCV C++ 进行二维码检测. 一.二维码检测 首先我们要先将图像进行预处理,通过灰度.滤波.二值化等操作提取出图像轮廓.在这里我还添加了形态学操作,消除噪点,有效将矩形区域连接起来. Mat gray; cvtColor(src, gray, COLOR_BGR2GRAY); Mat blur; GaussianBlur(gray, blur, Size(3, 3), 0); Mat bin;

  • C++ OpenCV实战之图像透视矫正

    目录 前言 一.图像预处理 二.轮廓提取 1.提取最外轮廓 2.提取矩形四个角点 3.将矩形角点排序 三.透视矫正 四.源码 前言 本文将使用OpenCV C++ 进行图像透视矫正. 一.图像预处理 原图如图所示.首先进行图像预处理.将图像进行灰度.滤波.二值化.形态学等操作,目的是为了下面的轮廓提取.在这里我还使用了形态学开.闭操作,目的是使整个二值图像连在一起.大家在做图像预处理时,可以根据图像特征自行处理. Mat gray; cvtColor(src, gray, COLOR_BGR2G

  • C++ OpenCV实现图像去水印功能

    目录 前言 一.水印定位 二.图像修复 三.效果显示 四.源码 总结 前言 本文将使用OpenCV C++ 进行简单图像水印去除.我们在网上download图片时,经常因为版权问题有水印.本案例通过编写算法进行简单水印去除. 一.水印定位 如图所示,图像左下角.右下角有水印.第一步,我们首先得定位水印所在位置. Mat gray; cvtColor(src, gray, COLOR_BGR2GRAY); //图像二值化,筛选出白色区域部分 Mat thresh; threshold(gray,

  • C++ OpenCV实战之制作九宫格图像

    目录 前言 一.九宫格图像 二.源码 三.效果显示 总结 前言 本文将使用OpenCV C++ 制作九宫格图像.其实原理很简单,就是将一张图像均等分成九份.然后将这九个小块按一定间隔(九宫格效果)拷贝到新画布上就可以啦. 一.九宫格图像 原图如图所示.本案例的需求是希望将图像均等分成九份,制作九宫格图像.首先得将原图均等分成九份. 如图所示.将原图均等分成九份,然后将这每一个小方块按照一定的间隔(九宫格效果)拷贝到新图像就可以了.具体算法思想请看源码注释. 二.源码 #include<iostr

  • C++ OpenCV实现图像修复功能

    目录 前言 一.OpenCV inpaint 二.源码 三.效果显示 前言 本文将使用OpenCV C++ 对有瑕疵的图像进行修复.OpenCV 提供了inpaint API可进行图像修复. 一.OpenCV inpaint 原图如图所示.本案例的需求是希望能够将图像上的红线给消除.OpenCV 提供的inpaint API能够实现这个效果. void inpaint( InputArray src, 原图 InputArray inpaintMask, 二进制掩模,指示要修复的像素 Outpu

  • 基于C++ OpenCV制作电子相册查看器

    目录 前言 一.图片读取 二.图片展示 三.键盘控制 四.效果显示 五.源码 总结 前言 本文将使用OpenCV C++ 制作电子相册查看器.类似于win10系统的“照片”功能.接下来就具体来看看是如何一步步的实现吧. 一.图片读取 我们想要一张张的查看文件夹下的图片,第一步就得读取将该文件夹下的所有图片. 如上图所示,为我创建的文件夹,该文件夹下有14张图片.接下来我们就编写代码读取该文件夹下的所有图片.将读取到的图片存储在images容器. //读取文件夹下所有图片 string filen

  • C++ OpenCV生成蒙太奇图像的示例详解

    目录 前言 一.输入模板图像 二.读取素材图像 三.生成蒙太奇模板 四.生成蒙太奇图像 五.源码 总结 前言 本文将使用OpenCV C++ 生成蒙太奇图像. 一.输入模板图像 原图如图所示.我们将对此图生成蒙太奇图像. Mat src = imread("Taylor.jpg"); if (src.empty()) { cout << "No image!" << endl; system("pause"); retur

  • C++ OpenCV实现抖音"蓝线挑战"特效

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

  • Python实现蓝线挑战特效的示例代码

    目录 1. 摄像头版本 2. 视频处理版本 在抖音曾经火了一阵子的蓝线挑战特效,其原理很简单:在蓝线经过后保留本帧的部分像素,形成蒙板图片,未经过处照常切换帧图片,再将蒙版图片贴到每帧图片上.本着我上我也行的想法,试着用opencv-python实现这个效果,做了摄像头版本和视频处理版本. 图源:抖音 图源: PPT 1. 摄像头版本 从上述描述可知,在摄像头版本中可规定每帧取固定宽度像素,如2个像素,假设视频尺寸为640*480,则需要480/2=240帧,若视频帧率(每秒的帧数)为30,则运

  • Android OpenGL ES 实现抖音传送带特效(原理解析)

    目录 抖音传送带特效原理 抖音传送带特效实现 抖音 APP 真是个好东西,不过也容易上瘾,老实说你的抖音是不是反复卸载又反复安装了,后来我也发现我的几个 leader 都不刷抖音,这令我挺吃惊的. 我刷抖音主要是为了看新闻,听一些大 V 讲历史,研究抖音的一些算法特效,最重要的是抖音提供了一个年轻人的视角去观察世界.另外,自己感兴趣的内容看多了,反而训练抖音推送更多类似的优质内容,大家可以反向利用抖音的这一特点. 至于我的 leader 老是强调刷抖音不好,对此我并不完全认同. 抖音传送带特效原

  • Android 实现抖音小游戏潜艇大挑战的思路详解

    <潜水艇大挑战>是抖音上的一款小游戏,以面部识别来驱动潜艇通过障碍物,最近特别火爆,相信很多人都玩过. 一时兴起自己用Android自定义View也撸了一个,发现只要有好的创意,不用高深的技术照样可以开发出好玩的应用.开发过程现拿出来与大家分享一下. 项目地址: https://github.com/vitaviva/ugame 基本思路 整个游戏视图可以分成三层: camera(相机):处理相机的preview以及人脸识别 background(后景):处理障碍物相关逻辑 foregroun

  • python gui开发——制作抖音无水印视频下载工具(附源码)

    hello,大家好啊,失踪人口回归了 [捂脸]!本次使用tkinter撰写一篇 抖音无水印视频下载,目的很纯粹,就是为了设置 微信状态视频.本篇博文中,我会写下我的代码撰写思路以及想写设计流程,代码放在了第四节,工具打包好放在了 蓝奏云,慢慢看,后面有链接. 一.准备工作 本次要用到以下依赖库:re json os random tkinter threading requests pillow 其中后两个需要安装后使用 二.预览 0.复制抖音分享短链接 1.启动 2.运行 3.结果 (小姐姐挺

  • iOS实现抖音点赞功能

    目录 前言 实现原理 三角形的贝塞尔曲线原理 代码实现 创建 CAShapeLayer 创建初始位置的贝塞尔path 结束 前言 很多人肯定都是玩过抖音的吧,那也肯定为了某位美女或者帅哥偷偷作死的点过小爱心.但是你肯定不知道怎么实现的吧,今天我来教你一手,仔细看. 本篇文章主要包含技术点: CAShapeLayer和贝赛尔曲线绘制三角形 组合动画的时间技巧 实现原理 首先 我们来详细分解一下这个动画 请仔细观察 我们来看单独的一个动画 请仔细观看 我设置10秒的duration 以便于大家能看清

  • 利用adb shell和node.js实现抖音自动抢红包功能(推荐)

    逻辑很简单,在抖音视频播完之后如果是红包视频,会跳出红包. 我们模拟逻辑如下: 点击屏幕中央,如果有红包打开红包,没有红包则暂停视频. 点击返回按钮,如果有红包关闭红包界面,没有红包提示再按一次退出(其实没退出). 进行上滑操作,进入下一个视频. 点击.返回.上滑,就这么三步行为,无论有红包没红包都成立,只要计算好时间就行. 代码 下面是一段 node.js 代码: touch.js var process = require('child_process'); function exec(sh

  • Android 仿抖音的评论列表的UI和效果的实现代码

    抖音是一款音乐创意短视频社交软件,是一个专注年轻人的15秒音乐短视频社区.用户可以通过这款软件选择歌曲,拍摄15秒的音乐短视频,形成自己的作品.此App已在Android各大应用商店和APP Store均有上线. 在design包里面 有一个 BottomSheetDialogFragment 这个Fragment,他已经帮我们处理好了手势,所以实现起来很简单.下面是代码: public class ItemListDialogFragment extends BottomSheetDialog

  • 抖音vbs表白代码大全 抖音vbscript表白代码使用方法

    当然斗音很热,这篇文章也有蹭热度的嫌疑. 我们以前就收录了类似这样的属于恶作剧的代码,其实就是判读如果不是你想要的结果就是死循环. 抖音vbs表白代码制作教程 步骤一: 在电脑上新建一个txt文件. 步骤二: 打开txt文件,复制以下代码粘贴进去(可以修改中文部分,其它代码不要动!).保存并关闭txt文件. Set Seven = WScript.CreateObject("WScript.Shell") strDesktop = Seven.SpecialFolders("

  • Android中模仿抖音加载框之两颗小球转动效果

    安卓版抖音v2.5加载框: 效果图如下所示: 本控件效果图: 使用方法 源码地址:Android仿抖音加载框之两颗小球转动控件 1.xml引用: <com.douyinloadingview.DYLoadingView android:id="@+id/dy3" android:layout_width="match_parent" android:layout_height="wrap_content" android:backgroun

随机推荐