使用 C/C++的OpenCV 實時播放火柴人愛心舞蹈動畫

使用 C++/OpenCV 實時播放火柴人愛心舞蹈動畫

本文將介紹如何使用 C++/OpenCV 庫實時創建一個動畫窗口:一個火柴人捧著愛心跳舞,同時另一個愛心從遠處飛來并逐漸變大。動畫會實時在 OpenCV 窗口中播放,直到用戶按下按鍵退出。
在這里插入圖片描述

準備工作

確保你的系統上已經安裝了 OpenCV 庫,并且配置好了 C++ 的編譯環境。

C++ 實時動畫代碼

以下代碼會創建一個窗口并直接在其中循環播放動畫。

stickman_heart_realtime.cpp:

#include <iostream>
#include <vector>
#include <cmath>
#include <string>
#include <opencv2/opencv.hpp>
#ifndef M_PI
const double M_PI = 3.14159265358979323846;
#endif
using namespace cv;
using namespace std;// --- 動畫參數 ---
const int WIDTH = 800;
const int HEIGHT = 600;
const int FPS = 30; // 動畫幀率 (Frames Per Second)
const Scalar BG_COLOR = Scalar(28, 28, 28); // 深灰色背景
const Scalar STICKMAN_COLOR = Scalar(255, 255, 255); // 白色火柴人
const Scalar HEART_COLOR = Scalar(70, 70, 255); // 紅色愛心 (BGR)
const int STICKMAN_SCALE = 40;
const Point STICKMAN_POS(WIDTH / 3, HEIGHT - 2 * STICKMAN_SCALE);/*** @brief 繪制火柴人* @param img 要繪制的圖像* @param pos 火柴人的基準位置 (腳底中心)* @param scale 控制火柴人大小* @param angle 身體的擺動角度*/
void drawStickman(Mat& img, Point pos, int scale, double angle = 0.0) {Point head_center = pos - Point(0, scale * 2);circle(img, head_center, scale / 2, STICKMAN_COLOR, 3, LINE_AA);Point body_top = head_center + Point(0, scale / 2);Point body_bottom = body_top + Point(0, scale);line(img, body_top, body_bottom, STICKMAN_COLOR, 3, LINE_AA);// 搖擺的手臂Point arm_joint = body_top + Point(0, scale / 10);Point arm_left = arm_joint + Point(-scale * 0.7 * cos(angle), scale * 0.7 * sin(angle));Point arm_right = arm_joint + Point(scale * 0.7 * cos(angle), scale * 0.7 * sin(angle));line(img, arm_joint, arm_left, STICKMAN_COLOR, 3, LINE_AA);line(img, arm_joint, arm_right, STICKMAN_COLOR, 3, LINE_AA);// 搖擺的腿Point leg_left = body_bottom + Point(-scale * 0.8* 1, scale * 0.8 * 1);Point leg_right = body_bottom + Point(scale * 0.8 *1, scale * 0.8 * 1);line(img, body_bottom, leg_left, STICKMAN_COLOR, 3, LINE_AA);line(img, body_bottom, leg_right, STICKMAN_COLOR, 3, LINE_AA);
}/*** @brief 繪制實心愛心* @param img 要繪制的圖像* @param center 愛心中心點* @param radius 愛心大小*/
void drawHeart(Mat& img, Point center, int radius) {vector<Point> heart_points;for (double t = 0; t <= 2 * M_PI; t += 0.01) {double x = center.x + radius * 1.2 * sin(t) * sin(t) * sin(t);double y = center.y - radius * (1.1 * cos(t) - 0.4 * cos(2 * t) - 0.2 * cos(3 * t) - 0.1 * cos(4 * t));heart_points.push_back(Point(x, y));}fillPoly(img, vector<vector<Point>>{heart_points}, HEART_COLOR, LINE_AA);
}int main() {// 在循環外創建窗口string winName = "Stickman Heart Dance";namedWindow(winName, WINDOW_AUTOSIZE);int frame = 0;// 動畫主循環while (true) {// 1. 創建每一幀的畫布Mat img(HEIGHT, WIDTH, CV_8UC3, BG_COLOR);// 2. 計算動畫參數// 火柴人跳舞動畫 (身體和四肢搖擺)double dance_angle = sin(2 * M_PI * frame / (FPS * 2.0)) * 0.8; // 搖擺角度drawStickman(img, STICKMAN_POS, STICKMAN_SCALE, dance_angle);// 火柴人手中捧著的愛心,隨著身體跳動double bounce = sin(2 * M_PI * frame / (FPS * 1.0)) * 5;Point holding_heart_offset = Point(0, -STICKMAN_SCALE * 2.5 + bounce);drawHeart(img, STICKMAN_POS + holding_heart_offset, STICKMAN_SCALE / 3);// 飛過來的愛心動畫int animation_duration = FPS * 5; // 動畫總時長為5秒if (frame < animation_duration) {double progress = static_cast<double>(frame) / animation_duration;// 初始大小和最終大小double start_radius = STICKMAN_SCALE * 0.1;double end_radius = STICKMAN_SCALE * 2.5;// 初始位置和最終位置Point start_pos(WIDTH * 0.9, HEIGHT * 0.2);Point end_pos = STICKMAN_POS + Point(STICKMAN_SCALE * 2, -STICKMAN_SCALE * 2.5);// 使用緩動函數 (ease-out) 使動畫更自然double ease_progress = 1 - pow(1 - progress, 3);int current_radius = static_cast<int>(start_radius + (end_radius - start_radius) * ease_progress);Point current_pos = start_pos * (1.0 - ease_progress) + end_pos * ease_progress;drawHeart(img, current_pos, current_radius);}// 添加操作提示putText(img, "Press 'q' or ESC to exit", Point(10, 25), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(200, 200, 200), 1, LINE_AA);// 3. 顯示當前幀imshow(winName, img);// 4. 控制幀率并等待按鍵// 計算每幀的延遲時間 (毫秒)int delay = 1000 / FPS;int key = waitKey(delay);// 如果按下 'q' 鍵或 ESC 鍵,則退出循環if (key == 'q' || key == 27) {break;}frame++; // 幀計數器增加}// 關閉所有窗口destroyAllWindows();cout << "Animation finished. Window closed." << endl;return 0;
}

代碼邏輯解析

  1. 窗口創建 (namedWindow): 在進入主循環之前,我們先創建一個窗口。這樣可以避免在每次循環時都重復創建和銷毀窗口,提高效率。

  2. 動畫主循環 (while(true)): 程序的核心是一個無限循環。在這個循環中,我們不斷地生成和顯示動畫的每一幀。

  3. 實時顯示 (imshow): 在循環的內部,我們用 imshow() 函數將繪制好的圖像 img 顯示到之前創建的窗口中。每次循環都會刷新窗口的內容,從而形成連續的動畫。

  4. 控制速度與響應 (waitKey): waitKey(delay) 是實現實時動畫的關鍵。

    • 控制速度: 它會使程序暫停 delay 毫秒。我們通過 1000 / FPS 計算出每幀應該停留的時間,從而精確控制動畫的播放速度。
    • 事件處理與響應: 在暫停期間,waitKey 還會處理窗口的事件,比如檢測鍵盤輸入。我們將它的返回值存入 key 變量。
  5. 退出條件: 我們檢查 key 的值。如果用戶按下了 ‘q’ 鍵(ASCII碼)或 Esc 鍵(ASCII碼為 27),while 循環就會通過 break 語句中斷,程序隨之結束。

如何編譯和運行

  1. 保存代碼: 將以上代碼保存為 stickman_heart_realtime.cpp
  2. 編譯 (使用g++):
    g++ stickman_heart_realtime.cpp -o stickman_app `pkg-config opencv4 --cflags --libs`
    
    (如果你的 OpenCV 不是版本4,可以嘗試 pkg-config opencv --cflags --libs)
  3. 運行:
    ./stickman_app
    

運行效果

運行程序后,你會看到一個窗口彈出,并開始播放動畫:

  • 一個白色的火柴人在深灰色的背景下左右搖擺四肢,模擬跳舞。
  • 他胸前捧著一個紅色的小愛心,隨著他的舞步上下跳動。
  • 一個更大的愛心從屏幕右上角緩緩飛入,它的軌跡是一條平滑的曲線,并且在飛行過程中體積不斷增大,最終停留在火柴人附近。
  • 動畫會一直循環播放。

當你想關閉時,請確保窗口是激活狀態(用鼠標點擊一下窗口),然后按下鍵盤上的 ‘q’ 鍵或 Esc 鍵即可退出程序。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/84580.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/84580.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/84580.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

復現論文報錯解決

文章目錄 一、 The detected CUDA version (12.9) mismatches the version that was used to compile PyTorch (11.8)二、error -- unsupported GNU version! gcc versions later than 11 are not supported!三、Unknown encoder libx264四、下載速度太慢、無法遞歸下載項目 一…

Python 實現 Web 靜態服務器(HTTP 協議)

目錄 一、在本地啟動 HTTP 服務器1. Windows 下安裝 node.js1&#xff09;下載安裝包2&#xff09;配置環境變量3&#xff09;安裝鏡像4&#xff09;node.js 的常用命令 2. 安裝 http-server 服務3. 使用 http-server 開啟服務1&#xff09;使用 http-server2&#xff09;詳解 …

MPMA:Preference Manipulation Attack Against Model Context Protocol

概要 MCP作為提供給LLM作為工具調用的標準化協議被廣泛應用&#xff0c;但是MCP在安全方面還比較脆弱。本文提出了一種MPMA攻擊方法通過在工具的名字或描述中插入具有操控性的文字、短語來操控LLM選擇MCP server的過程。 不了解MCP的具體細節可以看看我寫的這篇文章MCP 場景…

Vim 替換命令完整學習筆記

Vim 替換命令完整學習筆記 文章目錄 Vim 替換命令完整學習筆記1. 核心概念2. 替換命令基本語法2.1 基本格式2.2 分隔符選擇2.3 范圍指定 3. 替換標志詳解3.1 基礎標志3.2 高級標志3.3 標志組合 4. 正則表達式在替換中的應用4.1 基礎正則表達式4.2 字符類和量詞4.3 分組和引用 5…

@RequestBody和@ResponseBody注解的作用是什么

@RequestBody和@ResponseBody注解的作用是什么 文章目錄 @RequestBody和@ResponseBody注解的作用是什么@RequestBody和@ResponseBody注解的作用是什么SpringMVC的請求與響應模型1. 請求的處理流程1.1 DispatcherServlet作為入口1.2 Handler處理器與Controller1.3 HandlerAdapte…

質因數分解_java

什么是質因數&#xff1f; 說的通俗一點就是&#xff0c;這個數既是因數&#xff0c;又是質數。但是1不是質因數(不是質數)。然后比如122*2*3&#xff0c;里邊的2&#xff0c;3都是質數&#xff0c;并且也是12的因數&#xff0c;所以2、3就是12的質因數。 因為本人很菜&#xf…

SpringDoc集成到Springboot

1.Maven引入jar包 <dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-ui</artifactId><version>1.6.14</version> </dependency> 2.新建OpenApiConfig文件&#xff0c;代碼如下 package com.elan…

Memory Repair (五)

Compression Algorithm and Fuse Box Organization 通常情況下&#xff0c;這部分信息對于實現BISR&#xff08;內置自修復&#xff09;并非必需&#xff0c;但對于診斷問題可能有所幫助。 Compression and Fuse Box Organization Overview BISR controller采用的壓縮算法基于兩…

雙系統(win+linux)根目錄擴容(不掉GPU驅動)

先看效果&#xff0c;原來的根目錄僅50G&#xff0c;從/home節點分出擴容后變為250GB&#xff1b; 因為根分區是系統當前運行的文件系統&#xff0c;Linux系統啟動后會鎖定根分區&#xff0c;防止對其進行修改。這時使用系統內的工具&#xff08;如gparted&#xff09;調整根分…

oracle 23ai對象注釋新特性ANNOTATIONS

我們知道以前數據庫版本注釋方式是用COMMENT&#xff0c;如下 COMMENT ON COLUMN 表名.字段名 IS 字段注釋; oracle 23ai對象注釋有新增了ANNOTATIONS&#xff0c;比如創建如下表&#xff1a; SQL> create table test.t_user( id number, name varchar(200) ANNOTATIONS …

VMware 虛擬機開機自啟動配置指南

方法一&#xff1a;通過啟動文件夾設置&#xff08;簡單版&#xff09; 打開啟動文件夾&#xff1a; 按下 Win R 快捷鍵輸入 shell:startup 并回車 創建啟動腳本&#xff1a; 在打開的文件夾中右鍵新建一個文本文件命名為 vm_start.bat輸入以下內容&#xff1a; echo off &…

2025pmx文件怎么打開blender和虛幻

pmx文件怎么打開blender 前言 一坑接一坑。 意思很簡單&#xff0c;就是給Blender、3dsmax裝插件&#xff0c;然后就可以打開了。但是報錯就要多走很多錯路。 記錄一下。 內容 參考文章&#xff1a;https://blog.csdn.net/c858845275/article/details/144180555 我的Ble…

Kotlin基礎語法五

繼承與重載的open關鍵字 KT所有的類&#xff0c;默認是final修飾的&#xff0c;不能被繼承&#xff0c;和Java相反 open&#xff1a;移除final修飾 類型轉換 open class Person2(private val name: String) {fun showName() "父類 的姓名是【$name】"// KT所有的…

MySQL數據庫:關系型數據庫的基石

文章目錄 每日一句正能量前言一、MySQL簡介&#xff08;一&#xff09;什么是MySQL&#xff1f;&#xff08;二&#xff09;MySQL的歷史 二、MySQL的特點&#xff08;一&#xff09;開源與免費&#xff08;二&#xff09;高性能&#xff08;三&#xff09;跨平臺支持&#xff0…

【kafka】Golang實現分布式Masscan任務調度系統

要求: 輸出兩個程序,一個命令行程序(命令行參數用flag)和一個服務端程序。 命令行程序支持通過命令行參數配置下發IP或IP段、端口、掃描帶寬,然后將消息推送到kafka里面。 服務端程序: 從kafka消費者接收掃描任務信息通過調用masscan啟動探測任務,獲取進度和結果信息,…

ARM 和 x86_64是什么關系

什么是 ARM 和 x86_64&#xff1f; 它們都是 CPU 指令集架構&#xff08;ISA&#xff09; 指令集架構&#xff08;Instruction Set Architecture&#xff09;就是&#xff1a; CPU 能夠理解和執行的“語言”和“命令格式”。 類比解釋&#xff1a;指令集就像“語言” 類比對…

nginx配置中有無‘‘/’’的區別

在Nginx配置中&#xff0c;location指令末尾的斜杠/和proxy_pass目標地址末尾的斜杠/組合使用會產生顯著差異。以下是四種組合的區別詳解&#xff1a; ??核心區別對比表?? 配置方案匹配規則請求URI傳遞邏輯實際轉發效果示例location /api/ proxy_pass ...701/僅匹配/api/…

系統安全之身份認證

本篇我們對常用的身份認證協議做簡要的梳理&#xff0c;包括主流的 HTTP 相關認證協議以及證書密鑰對、新興的 WebAuthn 認證。 HTTP 協議認證 RFC 7235 中定義了 HTTP 協議的認證框架&#xff0c;要求在支持 HTTP 協議的服務器&#xff0c;如果訪問服務的身份驗證失敗&#…

部署http服務

使用flask搭建一個http服務&#xff0c;能夠通過本地的另外一個終端訪問對應接口&#xff0c;拿到服務端的計算結果 服務端&#xff1a; 創建一個test_http_dtw.py并運行 from flask import Flask, request, jsonifyapp Flask(__name__)# 示例分析函數 def analysis(data):…

WLAN 技術指南:從入門到原理

文章目錄 目錄 文章目錄 前言 一.WLAN 基本概念 有線側組網概念 AP-AC 組網方式 AC 連接方式 CAPWAP 協議 無線側組網概念 無線信道 ?編輯 BSS/SSID/BSSID ?編輯 VAP ESS 二.WLAN 組網架構 基本的 WLAN 組網架構 四.WLAN 工作原理 AP 上線 AP 獲取 IP 地址階段 CAP…