使用 C++/OpenCV 制作跳动的爱心动画

news2025/6/6 9:05:02

使用 C++/OpenCV 制作跳动的爱心动画

本文将引导你如何使用 C++ 和 OpenCV 库创建一个简单但有趣的跳动爱心动画。我们将通过绘制参数方程定义的爱心形状,并利用正弦函数来模拟心跳的缩放效果。
在这里插入图片描述


目录

  1. 简介
  2. 先决条件
  3. 核心概念
    • 参数方程绘制爱心
    • 动画循环
    • 模拟心跳效果
  4. 代码实现
  5. 代码详解
    • drawHeart 函数
    • main 函数
  6. 编译与运行
  7. 效果展示
  8. 总结与扩展

简介

动画是通过快速连续显示一系列静态图像来创建运动的幻觉。在这个项目中,我们将每一帧都绘制一个爱心,并通过周期性地改变爱心的大小来模拟“跳动”的效果。这是一个学习 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) 点,然后将这些点连接起来形成多边形,并填充颜色。

动画循环

动画的核心是一个循环,在每次迭代中:

  1. 清除或重新初始化画布。
  2. 根据当前时间或状态计算爱心的大小和/或位置。
  3. 在画布上绘制爱心。
  4. 显示画布。
  5. 短暂延迟,以控制动画速度。
  6. 检查退出条件(例如按键)。

模拟心跳效果

心跳是一个周期性的扩张和收缩过程。我们可以使用正弦函数来模拟这种大小变化。爱心的缩放比例 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
#endif

const 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*PI
        double 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 FPS
        if (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: 爱心的颜色。
  • 循环变量 t02 * 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 (推荐):

  1. 创建 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})
    
  2. 编译:
    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 的绘图功能和参数方程来创建形状,并通过周期性改变其属性来制作动画。

可以尝试的扩展:

  • 颜色变化: 让爱心的颜色随心跳一起脉动。
  • 更复杂的心跳: 模拟更真实的心跳曲线(例如,快速收缩,然后稍慢舒张)。
  • 背景效果: 添加动态背景或粒子效果。
  • 用户交互: 允许用户通过鼠标点击改变心跳速率或颜色。
  • 多个爱心: 绘制多个以不同节奏或相位跳动的爱心。

希望你喜欢这个教程!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2398760.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在Oxygen编辑器中使用DeepSeek

罗马尼亚公司研制开发的Oxygen编辑器怎样与国产大模型结合&#xff0c;这是今年我在tcworld大会上给大家的分享&#xff0c;需要ppt的朋友请私信联系 - 1 - Oxygen编辑器中的人工智能助手 Oxygen编辑器是罗马尼亚的Syncro Soft公司开发的一款结构化文档编辑器。 它是用来编写…

一、基础环境配置

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

论文阅读笔记——FLOW MATCHING FOR GENERATIVE MODELING

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

SQL Views(视图)

目录 Views Declaring Views Example: View Definition Example: Accessing a View Advantages of Views Triggers on Views Interpreting a View Insertion&#xff08;视图插入操作的解释&#xff09; The Trigger Views A view is a relation defined in terms of…

「卫星百科」“绿色守卫”高分六号

高分六号&#xff08;GF-6&#xff09;是中国高分辨率对地观测系统&#xff08;高分专项&#xff09;的重要组成卫星&#xff0c;于2018年6月2日成功发射。高分六号卫星凭借其高时空分辨率、红边波段、宽覆盖能力&#xff0c;在农业、生态、灾害等领域提供了重要的数据支撑。本…

秋招Day12 - 计算机网络 - IP

IP协议的定义和作用&#xff1f; IP协议用于在计算机网络中传递数据包&#xff0c;定义了数据包的格式和处理规则&#xff0c;确保数据能够从一个设备传递到另一个设备&#xff0c;中间可能经过多个不同的设备&#xff08;路由器&#xff09;。 IP协议有哪些作用&#xff1f;…

【前端】CSS面试八股

网上现有资料已经很丰富了&#xff0c;我挑了些自己押面试题时总结过的来写。 Q&#xff1a;回流和重绘 A&#xff1a; 回流reflow&#xff1a;计算元素的几何&#xff0c;引发layout重绘repaint&#xff1a;更新元素可见样式&#xff0c;引发paint 回流的成本比重绘高得多&…

Redis底层数据结构之字典(Dict)

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

佰力博科技与您探讨低温介电温谱测试仪的应用领域

低温介电温谱测试应用领域有如下&#xff1a; 一、电子材料&#xff1a; 低温介电温谱测试仪广泛应用于电子材料的性能测试&#xff0c;如陶瓷材料、半导体材料、压电材料等。通过该设备&#xff0c;可以评估材料在高温或低温环境下的介电性能&#xff0c;为材料的优化和应用提…

【办公类-48-04】202506每月电子屏台账汇总成docx-5(问卷星下载5月范围内容,自动获取excel文件名,并转移处理)

背景需求&#xff1a; 1-4月电子屏表格&#xff0c;都是用这个代码将EXCEL数据整理成分类成3个WORD表格。 【办公类-48-04】20250118每月电子屏台账汇总成docx-4&#xff08;提取EXCLE里面1月份的内容&#xff0c;自制月份文件夹&#xff09;-CSDN博客文章浏览阅读1.2k次&…

基于 ZYNQ UltraScale+ OV5640的高速图像传输系统设计,支持国产替代

引 言 随着电子信息技术的不断进步&#xff0c;人工智能、医 疗器械、机器视觉等领域都在高速发展 [1] &#xff0c;工业相机 是机器视觉系统中的一部分 [2] &#xff0c;对工业相机而言&#xff0c;传 输图像的速率、传输过程的抗干扰能力是其关键&#xff0c; 工业相…

demo_win10配置WSL、DockerDesktop环境,本地部署Dify,ngrok公网测试

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

TablePlus:一个跨平台的数据库管理工具

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

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&#xff08;装饰器&#xff09; 前言&#xff1a; 本案例通过李四举例&#xff0c;不改变源代码的情况下 对“才艺”进行增强。 摘要&#xff1a; 摘要&#xff1a; 装饰器模式是一种结构型设计模式&#xff0c;允许动态地为对象添加功能而不改变其…

HCIP-Datacom Core Technology V1.0_3 OSPF基础

动态路由协议简介 静态路由相比较动态路由有什么优点呢。 静态路由协议&#xff0c;当网络发生故障或者网络拓扑发生变更&#xff0c;它需要管理员手工配置去干预静态路由配置&#xff0c;但是动态路由协议&#xff0c;它能够及时自己感应网络拓扑变化&#xff0c;不路由选择…

工作自动化——工作自动提炼--智能编程——仙盟创梦IDE

工作自动化中的自动提炼、自动比对代码生成日志&#xff0c;为软件开发与项目管理带来诸多好处。 自动提炼能从复杂代码中精准提取关键信息&#xff0c;节省人工梳理时间&#xff0c;开发人员可快速把握核心逻辑&#xff0c;加速项目熟悉进程。自动比对代码则及时发现版本间差异…

大语言模型评测体系全解析(上篇):基础框架与综合评测平台

文章目录 一、评测体系的历史演进与技术底座&#xff08;一&#xff09;发展历程&#xff1a;从单任务到全维度评测1. 2018年前&#xff1a;单数据集时代的萌芽2. 2019-2023年&#xff1a;多任务基准的爆发式增长3. 2024年至今&#xff1a;动态化、场景化、多模态体系成型关键节…

生产环境MYSQL常见锁表场景

前言 锁表是我们在生产环境十分常见的问题之一&#xff0c;解决问题前需要先了解锁表产生的原因以找到解决方案&#xff0c;并制定方案以预防锁表&#xff0c;本文接下来会分别模拟元数据锁表&#xff08;MDL锁&#xff09;、行锁升级为表锁、死锁、**显示锁表 **四种锁表情形…