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

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

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


目录

  1. 简介
  2. 先决条件
  3. 核心概念
  4. 代码实现
  5. 代码详解
  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 的绘图功能和参数方程来创建形状,并通过周期性改变其属性来制作动画。

可以尝试的扩展:

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

希望你喜欢这个教程!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值