使用 C++/OpenCV 制作跳动的爱心动画
使用 C++/OpenCV 制作跳动的爱心动画
本文将引导你如何使用 C++ 和 OpenCV 库创建一个简单但有趣的跳动爱心动画。我们将通过绘制参数方程定义的爱心形状,并利用正弦函数来模拟心跳的缩放效果。
目录
- 简介
- 先决条件
- 核心概念
- 参数方程绘制爱心
- 动画循环
- 模拟心跳效果
- 代码实现
- 代码详解
drawHeart
函数main
函数
- 编译与运行
- 效果展示
- 总结与扩展
简介
动画是通过快速连续显示一系列静态图像来创建运动的幻觉。在这个项目中,我们将每一帧都绘制一个爱心,并通过周期性地改变爱心的大小来模拟“跳动”的效果。这是一个学习 OpenCV 绘图和基本动画原理的有趣练习。
先决条件
- C++ 编译器: 如 G++ (MinGW for Windows), Clang, MSVC。
- OpenCV 库: 版本 3.x 或 4.x,并已正确配置编译环境。
- CMake (推荐): 用于跨平台编译管理。
核心概念
参数方程绘制爱心
爱心的形状可以通过参数方程精确绘制。一个常用的爱心参数方程是:
x = 16 sin 3 ( t ) x = 16 \sin^3(t) x=16sin3(t)
y = 13 cos ( t ) − 5 cos ( 2 t ) − 2 cos ( 3 t ) − cos ( 4 t ) y = 13 \cos(t) - 5 \cos(2t) - 2 \cos(3t) - \cos(4t) y=13cos(t)−5cos(2t)−2cos(3t)−cos(4t)
其中 t t t 的范围从 0 0 0 到 2 π 2\pi 2π。我们将计算出一系列由这些方程产生的 ( x , y ) (x, y) (x,y) 点,然后将这些点连接起来形成多边形,并填充颜色。
动画循环
动画的核心是一个循环,在每次迭代中:
- 清除或重新初始化画布。
- 根据当前时间或状态计算爱心的大小和/或位置。
- 在画布上绘制爱心。
- 显示画布。
- 短暂延迟,以控制动画速度。
- 检查退出条件(例如按键)。
模拟心跳效果
心跳是一个周期性的扩张和收缩过程。我们可以使用正弦函数来模拟这种大小变化。爱心的缩放比例 scale
可以表示为:
current_scale = base_scale * (1 + amplitude * sin(frequency * time_variable))
其中:
base_scale
是爱心的基础大小。amplitude
控制跳动的幅度。frequency
控制跳动的快慢。time_variable
是一个随时间递增的变量(例如帧计数器)。
代码实现
#include <opencv2/opencv.hpp>
#include <vector>
#include <cmath> // For std::sin, std::cos, std::pow, M_PI (or define PI)#ifndef M_PI
#define M_PI 3.14159265358979323846
#endifconst int WINDOW_WIDTH = 600;
const int WINDOW_HEIGHT = 600;
const std::string WINDOW_NAME = "Beating Heart";// 函数:绘制一个爱心
void drawHeart(cv::Mat& image, double scale, const cv::Point& center, const cv::Scalar& color) {std::vector<cv::Point> heart_points;for (double t = 0; t <= 2 * M_PI; t += 0.01) { // t 从 0 到 2*PIdouble x_param = 16 * std::pow(std::sin(t), 3);double y_param = 13 * std::cos(t) - 5 * std::cos(2 * t) - 2 * std::cos(3 * t) - std::cos(4 * t);// 转换到 OpenCV 坐标系并应用缩放和中心偏移// 注意 y_param 是负的,因为参数方程通常y轴向上,而OpenCV图像y轴向下int cv_x = static_cast<int>(center.x + scale * x_param);int cv_y = static_cast<int>(center.y - scale * y_param); // 注意这里的负号heart_points.push_back(cv::Point(cv_x, cv_y));}if (!heart_points.empty()) {// cv::polylines(image, heart_points, true, color, 2); // 仅绘制轮廓cv::fillPoly(image, std::vector<std::vector<cv::Point>>{heart_points}, color); // 填充爱心}
}int main() {cv::Mat frame(WINDOW_HEIGHT, WINDOW_WIDTH, CV_8UC3, cv::Scalar(20, 20, 20)); // 深灰色背景double time = 0.0;double base_scale = 10.0; // 爱心的基础缩放系数double beat_amplitude = 0.2; // 心跳振幅 (相对于1的比例)double beat_frequency = 0.15; // 心跳频率 (数值越大跳动越快)cv::Scalar heart_color = cv::Scalar(0, 0, 255); // BGR: 红色while (true) {// 1. 清除画布 (用背景色重新填充)frame = cv::Scalar(20, 20, 20);// 2. 计算当前心跳的缩放比例// (1 + sin(t)) 范围是 [0, 2], (1 + sin(t))/2 范围是 [0, 1]// 这里我们用 1.0 +/- amplitude*sin(t) 来使大小在 (1-amplitude)*base_scale 和 (1+amplitude)*base_scale 之间变化double current_beat_factor = 1.0 + beat_amplitude * std::sin(beat_frequency * time);double current_scale = base_scale * current_beat_factor;// 3. 绘制爱心cv::Point center(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2 + 30); // 稍微向下移动一点,让爱心尖端更居中drawHeart(frame, current_scale, center, heart_color);// 4. 显示帧cv::imshow(WINDOW_NAME, frame);// 5. 延迟并检查按键int key = cv::waitKey(30); // 大约 33 FPSif (key == 27) { // ESC键break;}time += 1.0; // 更新时间变量}cv::destroyAllWindows();return 0;
}
代码详解
drawHeart
函数
cv::Mat& image
: 要在其上绘制爱心的画布。double scale
: 控制爱心整体大小的缩放因子。const cv::Point& center
: 爱心在画布上的中心点。const cv::Scalar& color
: 爱心的颜色。- 循环变量
t
从0
到2 * M_PI
步进,计算参数方程定义的点(x_param, y_param)
。 cv_x = static_cast<int>(center.x + scale * x_param);
cv_y = static_cast<int>(center.y - scale * y_param);
:将参数点转换为 OpenCV 窗口坐标。特别注意y_param
前的负号,这是因为参数方程中定义的 y 轴通常指向上方,而 OpenCV 图像的 y 轴指向下方。- 计算出的点存储在
std::vector<cv::Point> heart_points
中。 cv::fillPoly(...)
: 使用指定的颜色填充由heart_points
定义的多边形(爱心)。cv::polylines
可以用来只画轮廓。
main
函数
cv::Mat frame(...)
: 创建一个CV_8UC3
类型(8位无符号字符型,3通道彩色)的图像作为画布,并用深灰色初始化背景。time
: 一个简单的时间变量/帧计数器,用于驱动心跳动画的周期性变化。base_scale
: 爱心参数方程中固有大小的一个基础乘数。调整它会改变爱心的整体大小。beat_amplitude
: 控制心跳时大小变化的幅度。例如,0.2 表示大小在基础大小的 (1-0.2)倍 到 (1+0.2)倍之间变化。beat_frequency
: 控制心跳的快慢。值越大,跳动越快。while (true)
: 主动画循环。frame = cv::Scalar(20, 20, 20);
: 每帧开始时,用背景色重置(清空)画布。current_beat_factor = 1.0 + beat_amplitude * std::sin(beat_frequency * time);
: 使用std::sin
函数计算当前帧的缩放因子。sin
函数产生[-1, 1]
范围内的值,因此current_beat_factor
会在[1.0 - beat_amplitude, 1.0 + beat_amplitude]
之间平滑地变化。current_scale = base_scale * current_beat_factor;
: 计算最终应用于drawHeart
函数的缩放值。drawHeart(...)
: 调用函数绘制当前帧的爱心。cv::imshow(WINDOW_NAME, frame);
: 显示包含爱心的帧。cv::waitKey(30);
: 等待 30 毫秒。这既控制了动画的帧率,也为 OpenCV 处理窗口事件(如按键)提供了机会。如果用户按下 ESC 键(ASCII码 27),循环中断。time += 1.0;
: 递增时间变量,为下一帧的计算做准备。
cv::destroyAllWindows();
: 关闭所有 OpenCV 创建的窗口。
编译与运行
假设你的 C++ 文件名为 beating_heart.cpp
。
使用 CMake (推荐):
- 创建
CMakeLists.txt
文件:cmake_minimum_required(VERSION 3.10) project(BeatingHeart)set(CMAKE_CXX_STANDARD 14) # C++14 或更高find_package(OpenCV REQUIRED)include_directories(${OpenCV_INCLUDE_DIRS})add_executable(BeatingHeartApp beating_heart.cpp) target_link_libraries(BeatingHeartApp ${OpenCV_LIBS})
- 编译:
mkdir build && cd build cmake .. make # 或者在 Visual Studio 中打开生成的项目并编译 ./BeatingHeartApp # Linux/macOS # .\Release\BeatingHeartApp.exe # Windows (Visual Studio Release build)
直接使用 g++ (Linux/macOS):
g++ beating_heart.cpp -o BeatingHeartApp $(pkg-config --cflags --libs opencv4)
./BeatingHeartApp
(如果你的 pkg-config
对应 OpenCV 3.x,请使用 opencv
而不是 opencv4
)
效果展示
运行程序后,你将看到一个窗口,其中有一个红色的爱心在深灰色背景上平滑地放大和缩小,模拟心跳的效果。按 ESC
键可以关闭窗口并退出程序。
总结与扩展
通过这个简单的项目,我们学习了如何使用 OpenCV 的绘图功能和参数方程来创建形状,并通过周期性改变其属性来制作动画。
可以尝试的扩展:
- 颜色变化: 让爱心的颜色随心跳一起脉动。
- 更复杂的心跳: 模拟更真实的心跳曲线(例如,快速收缩,然后稍慢舒张)。
- 背景效果: 添加动态背景或粒子效果。
- 用户交互: 允许用户通过鼠标点击改变心跳速率或颜色。
- 多个爱心: 绘制多个以不同节奏或相位跳动的爱心。
希望你喜欢这个教程!
相关文章:

使用 C++/OpenCV 制作跳动的爱心动画
使用 C/OpenCV 制作跳动的爱心动画 本文将引导你如何使用 C 和 OpenCV 库创建一个简单但有趣的跳动爱心动画。我们将通过绘制参数方程定义的爱心形状,并利用正弦函数来模拟心跳的缩放效果。 目录 简介先决条件核心概念 参数方程绘制爱心动画循环模拟心跳效果 代码…...
Go Modules 详解 -《Go语言实战指南》
Go Modules(简称 go mod)是 Go 官方推出的包依赖管理系统,自 Go 1.11 起引入,Go 1.16 起成为默认方式,取代了旧的 GOPATH 模式。 本章将全面讲解 Go Modules 的基本原理、使用方法以及常见问题处理。 一、Go Modules 简…...

在Oxygen编辑器中使用DeepSeek
罗马尼亚公司研制开发的Oxygen编辑器怎样与国产大模型结合,这是今年我在tcworld大会上给大家的分享,需要ppt的朋友请私信联系 - 1 - Oxygen编辑器中的人工智能助手 Oxygen编辑器是罗马尼亚的Syncro Soft公司开发的一款结构化文档编辑器。 它是用来编写…...
【LeetCode 热题100】BFS/DFS 实战:岛屿数量 腐烂的橘子(力扣200 / 994 )(Go语言版)
🌊 BFS/DFS 实战:岛屿数量 & 腐烂的橘子(LeetCode 200 & 994) 两道图论基础题,涉及 BFS 与 DFS 的应用,主要用于掌握二维网格中遍历与标记访问的技巧: 🏝️ 200. 岛屿数量…...

一、基础环境配置
一、虚拟机 主:192.168.200.200 从:192.168.200.201 从:192.168.200.202 二、docker docker基础搭建,有不会的自行百度。 1.目录结构 /opt/software:软件包/opt/module:解压包,自定义脚本…...

论文阅读笔记——FLOW MATCHING FOR GENERATIVE MODELING
Flow Matching 论文 扩散模型:根据中心极限定理,对原始图像不断加高斯噪声,最终将原始信号破坏为近似的标准正态分布。这其中每一步都构造为条件高斯分布,形成离散的马尔科夫链。再通过逐步去噪得到原始图像。 Flow matching 采取…...

SQL Views(视图)
目录 Views Declaring Views Example: View Definition Example: Accessing a View Advantages of Views Triggers on Views Interpreting a View Insertion(视图插入操作的解释) The Trigger Views A view is a relation defined in terms of…...

「卫星百科」“绿色守卫”高分六号
高分六号(GF-6)是中国高分辨率对地观测系统(高分专项)的重要组成卫星,于2018年6月2日成功发射。高分六号卫星凭借其高时空分辨率、红边波段、宽覆盖能力,在农业、生态、灾害等领域提供了重要的数据支撑。本…...

秋招Day12 - 计算机网络 - IP
IP协议的定义和作用? IP协议用于在计算机网络中传递数据包,定义了数据包的格式和处理规则,确保数据能够从一个设备传递到另一个设备,中间可能经过多个不同的设备(路由器)。 IP协议有哪些作用?…...
Servlet 快速入门
文章目录 概念SpringBoot 测试案例执行原理传统 Servlet在 SpringBoot (嵌入式 Tomcat Spring MVC) 中请求从浏览器到业务代码的完整步骤关键点流程图 参考 概念 运行在服务器端的小程序, Servlet 就是一个接口,定义 Java 类被浏…...

【前端】CSS面试八股
网上现有资料已经很丰富了,我挑了些自己押面试题时总结过的来写。 Q:回流和重绘 A: 回流reflow:计算元素的几何,引发layout重绘repaint:更新元素可见样式,引发paint 回流的成本比重绘高得多&…...
[蓝桥杯]找到给定字符串中的不同字符
题目描述 在不考虑字符排列的条件下,对于相差只有一个字符的两个字符串,实现一个算法来识别相差的那个字符。要求如下: 当传入的字符串为 aad 和 ad 时,结果为 a。 当传入的字符串为 aaabccdd 和 abdcacade 时,结果为…...

Redis底层数据结构之字典(Dict)
Dict基本结构 Dict我们可以想象成目录,要翻看什么内容,直接通过目录能找到页数,翻过去看。如果没有目录,我们需要一页一页往后翻,这样时间复杂度就与遍历的O(n)一样了,而用了Dict我们就可以在O(1)的时间复杂…...

佰力博科技与您探讨低温介电温谱测试仪的应用领域
低温介电温谱测试应用领域有如下: 一、电子材料: 低温介电温谱测试仪广泛应用于电子材料的性能测试,如陶瓷材料、半导体材料、压电材料等。通过该设备,可以评估材料在高温或低温环境下的介电性能,为材料的优化和应用提…...
ubuntu之开机自启frpc
在 Ubuntu 系统中为 frpc 设置开机自启(以 frpc -c frpc.toml 命令为例),可以通过 systemd 服务实现。以下是详细步骤: 创建 systemd 服务文件 sudo vim /etc/systemd/system/frpc.service 写入以下内容(根据你的路…...

【办公类-48-04】202506每月电子屏台账汇总成docx-5(问卷星下载5月范围内容,自动获取excel文件名,并转移处理)
背景需求: 1-4月电子屏表格,都是用这个代码将EXCEL数据整理成分类成3个WORD表格。 【办公类-48-04】20250118每月电子屏台账汇总成docx-4(提取EXCLE里面1月份的内容,自制月份文件夹)-CSDN博客文章浏览阅读1.2k次&…...
对 `llamafactory-cli api -h` 输出的详细解读
llamafactory-cli 是 LlamaFactory 项目提供的命令行接口工具,它允许用户通过命令行参数来配置和运行大型语言模型的各种任务,如预训练(PT)、有监督微调(SFT)、奖励模型训练(RM)、基…...

基于 ZYNQ UltraScale+ OV5640的高速图像传输系统设计,支持国产替代
引 言 随着电子信息技术的不断进步,人工智能、医 疗器械、机器视觉等领域都在高速发展 [1] ,工业相机 是机器视觉系统中的一部分 [2] ,对工业相机而言,传 输图像的速率、传输过程的抗干扰能力是其关键, 工业相…...

demo_win10配置WSL、DockerDesktop环境,本地部署Dify,ngrok公网测试
win10配置WSL、DockerDesktop环境,本地部署Dify,ngrok分享测试 一、配置WSL 1.1 开启Hyper-V 安装WSL2首先要保证操作系统可以开启hyper-v功能,默认支持开启hyper-v的版本为:Windows11企业版、专业版或教育版,而家庭版是不支持…...

TablePlus:一个跨平台的数据库管理工具
TablePlus 是一款现代化的跨平台(Window、Linux、macOS、iOS)数据库管理工具,提供直观的界面和强大的功能,可以帮助用户轻松管理和操作数据库。 TablePlus 免费版可以永久使用,但是只能同时打开 2 个连接窗口ÿ…...

SQL Indexes(索引)
目录 Indexes Using Clustered Indexes Using Nonclustered Indexes Declaring Indexes Using Indexes Finding Rows Without Indexes Finding Rows in a Heap with a Nonclustered Index Finding Rows in a Clustered Index Finding Rows in a Clustered Index with …...

Axure 基础入门
目录 认识产品经理 项目团队* 基本概述 认识产品经理 A公司产品经理 B公司产品经理 C公司产品经理 D公司产品经理 产品经理工作范围 产品经理工作流程* 产品经理的职责 产品经理的分类 产品经理能力要求 产品工具 产品体验报告 原型设计介绍 原型设计概述 为…...

结构型设计模式之Decorator(装饰器)
结构型设计模式之Decorator(装饰器) 前言: 本案例通过李四举例,不改变源代码的情况下 对“才艺”进行增强。 摘要: 摘要: 装饰器模式是一种结构型设计模式,允许动态地为对象添加功能而不改变其…...

HCIP-Datacom Core Technology V1.0_3 OSPF基础
动态路由协议简介 静态路由相比较动态路由有什么优点呢。 静态路由协议,当网络发生故障或者网络拓扑发生变更,它需要管理员手工配置去干预静态路由配置,但是动态路由协议,它能够及时自己感应网络拓扑变化,不路由选择…...

工作自动化——工作自动提炼--智能编程——仙盟创梦IDE
工作自动化中的自动提炼、自动比对代码生成日志,为软件开发与项目管理带来诸多好处。 自动提炼能从复杂代码中精准提取关键信息,节省人工梳理时间,开发人员可快速把握核心逻辑,加速项目熟悉进程。自动比对代码则及时发现版本间差异…...
go语言学习 第 2 章:变量与数据类型
第 2 章:变量与数据类型 在 Go 语言中,变量和数据类型是构建程序的基础。理解它们的使用方式和特性,对于编写高效、可维护的代码至关重要。本章将详细介绍变量的声明、初始化、使用以及 Go 语言中的各种数据类型。 一、变量的声明与初始化 …...

大语言模型评测体系全解析(上篇):基础框架与综合评测平台
文章目录 一、评测体系的历史演进与技术底座(一)发展历程:从单任务到全维度评测1. 2018年前:单数据集时代的萌芽2. 2019-2023年:多任务基准的爆发式增长3. 2024年至今:动态化、场景化、多模态体系成型关键节…...
Spring Event(事件驱动机制)
一、Spring Event 应用场景 1. 业务解耦 当一个业务操作触发多个后续动作时,用事件解耦各个动作,避免代码耦合。 比如:用户注册后同时发送欢迎邮件、积分赠送、日志记录等,这些逻辑可以通过事件发布多个监听器异步处理。 2. 跨模…...
Fisher准则例题——给定类内散度矩阵和类样本均值
设有两类样本,两类样本的类内散度矩阵分别为 S 1 ( 1 1 / 2 1 / 2 1 ) , S 2 ( 1 − 1 / 2 − 1 / 2 1 ) S_1 \begin{pmatrix} 1 & 1/2 \\ 1/2 & 1 \end{pmatrix}, \quad S_2 \begin{pmatrix} 1 & -1/2 \\ -1/2 & 1 \end{pmatrix} S1(11/21…...
MySQL数据库中INNODB表数据的备份与恢复
使用数据库时,其中非常重要的一块内容就是数据的安全,而保障数据安全的重要手段是数据备份与还原恢复。目前,我们主要的备份手段有逻辑备份、物理备份,逻辑备份一般适用范围很广,可以适用于解决不同版本间的备份与恢复,但一般执行时间长,而且备份占用空间大。这里介绍一…...