OpenCV实现“蓝线挑战“特效
原理
算法原理可以分为三个流程:
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:生成的定格图像。由于生成的定格图像是从顶往下逐行扫描,故在扫描线下的像素为0src2:原视频帧图像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:生成的定格图像。由于生成的定格图像是从顶往下逐行扫描,故在扫描线下的像素为0src2:原视频帧图像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实现“蓝线挑战“特效
原理 算法原理可以分为三个流程: 1、将视频(图像)从(顶->底)或(左->右)逐行(列)扫描图像。 2、将扫描完成的行(列)像素重新生成定格图像…...
容器管理工具 Docker生态架构及部署
目录 一、Docker生态架构 1.1 Docker Containers Are Everywhere 1.2 生态架构 1.2.1 Docker Host 1.2.2 Docker daemon 1.2.3 Registry 1.2.4 Docker client 1.2.5 Image 1.2.6 Container 1.2.7 Docker Dashboard 1.3 Docker版本 二、Docker部署 2.1 使用YUM源部署…...
js判断数据类型的方法
简单数据类型用:typeof, // 可以直接typeof空格接数据的方式,也可以typeof(数据)的方式使用 console.log(typeof ""); //string(检验字符串没问题) console.log(typeof 1); //number(检验数字没问题) console.log(typ…...
达梦数据库随系统开机自动启动脚本
写一个脚本,实现在服务器开机后自动启动达梦数据库的功能。 1. 在/etc/init.d/目录下,编写脚本,并将脚本命名为startdm.sh。脚本内容实现如下: #!/bin/bash #chkconfig:2345 80 90 #decription:启动达梦# 切换到 dmdba 用户 su …...
Python开发利器之VS Code
Python官方提供了一个Python集成开发环境(IDE): IDLE (Integrated Development and Learning Environment)。 它提供了一个图形用户界面,可以让开发者编写、调试和执行Python程序。IDLE包含Python解释器、代码编辑器、调试器和文件…...
【Axure视频教程】输入框控制滑动评分条
今天教大家在Axure里如何制作输入框控制滑动评分条的原型模板,可以通过鼠标左右拖动滑块,也可以点击条形让滑块移动到指定位置,标签和输入框里会返回具体的分值,分值由滑块所在的位置动态计算而成;也可以在输入框里输入…...
【学习笔记】[AGC064C] Erase and Divide Game
有点难😅,看到比自己低一级的选手场切这道题就更绷不住了😇 考虑 从低到高位 建立 trie \text{trie} trie 树,但是因为是对反串建立的,所以编号连续的点在 trie \text{trie} trie 树上的位置是分散的😅 …...
算法通关村-----数组中元素出现次数问题
数组中出现次数超过一半的数字 问题描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。你可以假设数组是非空的,并且给定的数组总是存在多数元素。详见剑指offer39 问题分析 最直接的方式就是使用hashMap,遍历给定数组,…...
Qt-键盘消息的传递-键盘消息的获取-C++
文章目录 1.概述2.焦点3.强制获取键盘消息4.键盘常用组合方法5.总结 1.概述 QKeyEvent 类用来描述一个键盘事件。当键盘按键被按下或者被释放时,键盘事件便会被发送给拥有键盘输人焦点的部件。 QKeyEvent 的 key() 函数可以获取具体的按键,对于 Qt 中给…...
数据结构与算法(五)--链表概念以及向链表添加元素
一、前言 今天我们学习另一种非常重要的线性数据结构–链表,之前我们已经学习了三种线性数据结构,分别是动态数组,栈和队列。其中队列我们额外学习了队列的另一种实现方式–循环队列。其实我们自己实现过前三个数据结构就知道,它…...
计算机视觉与深度学习-图像分割-视觉识别任务02-目标检测-【北邮鲁鹏】
目录标题 参考目标检测定义深度学习对目标检测的作用单目标检测多任务框架多任务损失预训练模型姿态估计 多目标检测问题滑动窗口(Sliding Window)滑动窗口缺点 AdaBoost(Adaptive Boosting)参考 区域建议 selective search 思想慢…...
Flink——Flink检查点(checkpoint)、保存点(savepoint)的区别与联系
Flink checkpoint Checkpoint是Flink实现容错机制最核心的功能,能够根据配置周期性地基于Stream中各个Operator的状态来生成Snapshot,从而将这些状态数据定期持久化存储下来,从而将这些状态数据定期持久化存储下来,当Flink程序一…...
[篇五章五]-如何禁用 Windows Defender-我的创作纪念日
################################################## 目录 禁用掉烦人的 Windows Defender 在本地组策略编辑器中禁用 Windows Defende 关闭 Microsoft Defender 防病毒 禁止 Defender 开机自动运行 重新激活 Windows Defender #######################################…...
什么情况下使用微服务?
单体架构图参考网络: 1. 什么是单体应用 单体应用就是将应用程序的所有功能都打包成一个独立的单元,最终以一个WAR包或JAR包存在,没有外部的任何依赖,里面包含DAO、Service、UI等所有的逻辑。 优点: 1&…...
【Linux】Ubuntu美化主题【教程】
【Linux】Ubuntu美化主题【教程】 文章目录 【Linux】Ubuntu美化主题【教程】1. 安装优化工具Tweak2.下载自己喜欢的主题3. 下载自己喜欢的iconReference 1. 安装优化工具Tweak 首先安装优化工具Tweak sudo apt-get install gnome-tweak-tool安装完毕后在菜单中打开Tweak 然后…...
spring-boot2.x,使用EnableWebMvc注解导致的自定义HttpMessageConverters不可用
在json对象转换方面,springboot默认使用的是MappingJackson2HttpMessageConverter。常规需求,在工程中使用阿里的FastJson作为json对象的转换器。 FastJson SerializerFeatures WriteNullListAsEmpty :List字段如果为null,输出为[],而非nu…...
2023-09-20 Android CheckBox 让文字显示在选择框的左边
一、CheckBox 让文字在选择框的左边 ,在布局文件里面添加下面一行就可以。 android:layoutDirection"rtl" 即可实现 android:paddingStart"10dp" 设置框文间的间距 二、使用的是left to right <attr name"layoutDirection">&…...
目标检测YOLO实战应用案例100讲-基于改进YOLOv5的口罩人脸检测
目录 前言 国内外研究现状 目标检测研究发展 国内外口罩人脸检测研究现状...
CentOS7 yum安装报错:“Could not resolve host: mirrorlist.centos.org; Unknown error“
虚拟机通过yum安装东西的时候弹出这个错误: 1、查看安装在本机的网卡 网卡ens33处于disconnected的状态 nmcli d2、输入命令: nmtui3、选择网卡,然后点击edit 4、移动到Automatically connect按空格键选择,然后移动到OK键按空格…...
关于token续签
通常我们会对token设置一个有效期,于是,就有了token续签的问题。由于token并没有续时机制,如果不能及时的替换掉过期的token,可能会拦截用户正常的请求,用户只能重新登录,如果提交的信息量很大,…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
