OpenCV C++ 心形雨動畫

?? OpenCV C++ 心形雨動畫 ??

本文將引導你使用 C++ 和 OpenCV 庫創建一個可愛的心形雨動畫。在這個動畫中,心形會從屏幕頂部的隨機位置落下,模擬下雨的效果。使用opencv定制自己的專屬背景
在這里插入圖片描述

目錄

  1. 簡介
  2. 先決條件
  3. 核心概念
  4. 實現步驟
    • 創建項目
    • 定義心形結構體
    • 繪制心形的函數
    • 主動畫循環
    • 完整代碼示例
  5. 編譯和運行
  6. 效果展示
  7. 進一步的改進
  8. 總結

簡介

我們將創建一個窗口,在窗口中,不同大小和顏色的心形會從頂部隨機出現并向下飄落。這是一個有趣的小項目,可以幫助理解 OpenCV 的基本繪圖、事件處理和動畫循環。


先決條件

在開始之前,請確保你具備以下條件:

  • C++ 編譯器:如 GCC (MinGW for Windows), Clang, 或 MSVC。
  • OpenCV 庫:版本 3.x 或 4.x 已安裝并配置好編譯環境。
  • 基本的 C++ 知識:包括變量、循環、函數、結構體/類以及 STL (如 std::vector)。
  • 基本的 OpenCV 知識:了解 cv::Mat, cv::Point, cv::Scalar 以及窗口和繪圖函數。

核心概念

  • 心形表示:我們將通過繪制一個由特定點集定義的多邊形來創建一個心形。
  • 動畫幀:動畫是通過連續顯示略有不同的圖像(幀)來創建運動的錯覺。
  • 對象狀態:每個心形都有自己的位置、大小、顏色和下落速度。
  • 隨機生成:心形的初始位置、大小、顏色和速度將隨機生成,以獲得更自然的效果。
  • 主循環
    1. 清除上一幀的內容(或創建新畫布)。
    2. 隨機生成新的心形。
    3. 更新所有現有心形的位置。
    4. 繪制所有心形到當前幀。
    5. 顯示當前幀。
    6. 移除超出屏幕的心形。
    7. 短暫延遲后重復。

實現步驟

創建項目

首先,創建一個 C++ 項目,并確保你的構建系統(如 CMake 或直接使用 g++)能夠鏈接到 OpenCV 庫。

定義心形結構體

我們需要一個結構體來存儲每個心形的信息:

#include <opencv2/opencv.hpp> // 主要的OpenCV頭文件
#include <vector>             // 用于存儲心形
#include <random>             // 用于生成隨機數
#include <iostream>           // 用于輸出// 定義心形的屬性
struct Heart {cv::Point position; // 心形中心點當前位置int size;           // 心形大小cv::Scalar color;   // 心形顏色 (BGR格式)double speed;       // 心形下落速度
};

繪制心形的函數

我們將創建一個函數,根據給定的中心點、大小和顏色來繪制一個心形。心形可以通過 cv::fillPoly 繪制一個填充的多邊形來近似。

// 繪制單個心形
void drawHeart(cv::Mat& image, cv::Point center, int size, const cv::Scalar& color) {// 定義心形輪廓點(相對于中心點)// 這些點可以調整以獲得你喜歡的心形形狀std::vector<cv::Point> points;points.push_back(cv::Point(center.x, center.y + size / 2));                         // 底部尖端points.push_back(cv::Point(center.x - size / 2, center.y - size / 5));              // 左側下方點points.push_back(cv::Point(center.x - size / 2, center.y - size / 2));              // 左側中間點points.push_back(cv::Point(center.x - size / 4, center.y - (size * 4) / 5));        // 左側上方點(靠近凹陷處)points.push_back(cv::Point(center.x, center.y - size / 2));                         // 頂部凹陷處最低點points.push_back(cv::Point(center.x + size / 4, center.y - (size * 4) / 5));        // 右側上方點points.push_back(cv::Point(center.x + size / 2, center.y - size / 2));              // 右側中間點points.push_back(cv::Point(center.x + size / 2, center.y - size / 5));              // 右側下方點// 轉換成OpenCV fillPoly需要的格式const cv::Point* pts = (const cv::Point*)cv::Mat(points).data;int npts = points.size();// 繪制填充的心形cv::fillPoly(image, &pts, &npts, 1, color, cv::LINE_AA);
}

主動畫循環

這是程序的核心部分,負責生成、更新、繪制和顯示心形。

int main() {int windowWidth = 800;int windowHeight = 600;std::string windowName = "?? Heart Rain Animation ??";// 初始化隨機數生成器std::random_device rd;std::mt19937 gen(rd());std::uniform_int_distribution<> distribX(0, windowWidth); // X坐標std::uniform_int_distribution<> distribSize(15, 40);      // 心形大小std::uniform_real_distribution<> distribSpeed(1.0, 5.0);  // 下落速度std::uniform_int_distribution<> distribColorVal(100, 255); // 用于粉色/紅色系std::uniform_int_distribution<> distribSpawnChance(0, 100); // 生成新心形的概率std::vector<Heart> hearts;cv::namedWindow(windowName, cv::WINDOW_AUTOSIZE);while (true) {// 1. 創建一個黑色的畫布作為當前幀cv::Mat frame = cv::Mat::zeros(windowHeight, windowWidth, CV_8UC3);// 2. 隨機生成新的心形// 每幀有一定概率生成新的心形(例如15%的概率)if (distribSpawnChance(gen) < 15) { // 可以調整這個概率Heart newHeart;newHeart.position.x = distribX(gen);newHeart.position.y = 0; // 從頂部開始newHeart.size = distribSize(gen);newHeart.speed = distribSpeed(gen);// 生成粉紅色系或紅色的心形// BGR: (Blue, Green, Red)// 為了粉色/紅色,保持藍色通道較低,綠色適中,紅色較高int blue = distribColorVal(gen) / 3; // 較低的藍色值int green = distribColorVal(gen) / 2; // 適中的綠色值 (可以更低)int red = distribColorVal(gen);    // 較高的紅色值newHeart.color = cv::Scalar(blue, green, red);hearts.push_back(newHeart);}// 3. 更新并繪制所有心形for (size_t i = 0; i < hearts.size(); ++i) {// 更新位置hearts[i].position.y += hearts[i].speed;// 繪制心形drawHeart(frame, hearts[i].position, hearts[i].size, hearts[i].color);}// 4. 移除超出屏幕的心形 (從后往前遍歷以便安全刪除)for (int i = hearts.size() - 1; i >= 0; --i) {if (hearts[i].position.y - hearts[i].size > windowHeight) { // 完全移出底部hearts.erase(hearts.begin() + i);}}/* 或者使用 remove_if 和 erase-remove idiom (更C++風格)hearts.erase(std::remove_if(hearts.begin(), hearts.end(),[&](const Heart& h){return h.position.y - h.size > windowHeight;}), hearts.end());*/// 5. 顯示幀cv::imshow(windowName, frame);// 6. 等待按鍵,30毫秒延遲,如果按下ESC則退出int key = cv::waitKey(30); // 約33 FPSif (key == 27) { // ESC 鍵的ASCII碼break;}}cv::destroyAllWindows();return 0;
}

完整代碼示例

將以上片段組合起來,形成一個完整的 .cpp 文件。

#include <opencv2/opencv.hpp>
#include <vector>
#include <random>
#include <iostream> // 如果需要調試輸出// 定義心形的屬性
struct Heart {cv::Point position;int size;cv::Scalar color;double speed;
};// 繪制單個心形
void drawHeart(cv::Mat& image, cv::Point center, int size, const cv::Scalar& color) {std::vector<cv::Point> points;// 為了讓心形看起來更正,調整y坐標的偏移int y_offset = size / 10; // 輕微向上調整心形繪制的視覺中心center.y -= y_offset;points.push_back(cv::Point(center.x, center.y + size / 2));                     points.push_back(cv::Point(center.x - size / 2, center.y - size / 5));          points.push_back(cv::Point(center.x - size / 2, center.y - size / 2));          points.push_back(cv::Point(center.x - size / 4, center.y - (size * 4) / 5));    points.push_back(cv::Point(center.x, center.y - size / 2));                     points.push_back(cv::Point(center.x + size / 4, center.y - (size * 4) / 5));    points.push_back(cv::Point(center.x + size / 2, center.y - size / 2));          points.push_back(cv::Point(center.x + size / 2, center.y - size / 5));          const cv::Point* pts = (const cv::Point*)cv::Mat(points).data;int npts = points.size();cv::fillPoly(image, &pts, &npts, 1, color, cv::LINE_AA);
}int main() {int windowWidth = 800;int windowHeight = 600;std::string windowName = "?? Heart Rain Animation ??";std::random_device rd;std::mt19937 gen(rd());std::uniform_int_distribution<> distribX(0, windowWidth);std::uniform_int_distribution<> distribSize(15, 40);std::uniform_real_distribution<> distribSpeed(1.0, 5.0);std::uniform_int_distribution<> distribColorComponent(0, 150); // 用于B和G通道std::uniform_int_distribution<> distribRedComponent(200, 255); // 用于R通道std::uniform_int_distribution<> distribSpawnChance(0, 100);std::vector<Heart> hearts;cv::namedWindow(windowName, cv::WINDOW_AUTOSIZE);while (true) {cv::Mat frame = cv::Mat::zeros(windowHeight, windowWidth, CV_8UC3);if (distribSpawnChance(gen) < 15) {Heart newHeart;newHeart.position.x = distribX(gen);newHeart.position.y = 0; // 從頂部開始,但視覺上可能需要調整到剛好在屏幕外開始newHeart.size = distribSize(gen);newHeart.speed = distribSpeed(gen);newHeart.color = cv::Scalar(distribColorComponent(gen),       // BluedistribColorComponent(gen),       // GreendistribRedComponent(gen)          // Red (ensuring it's reddish/pinkish));hearts.push_back(newHeart);}for (size_t i = 0; i < hearts.size(); ++i) {hearts[i].position.y += hearts[i].speed;drawHeart(frame, hearts[i].position, hearts[i].size, hearts[i].color);}for (int i = hearts.size() - 1; i >= 0; --i) {if (hearts[i].position.y - (hearts[i].size * 4) / 5 > windowHeight) { // 判斷心形的"最高點"是否已過屏幕hearts.erase(hearts.begin() + i);}}cv::imshow(windowName, frame);int key = cv::waitKey(30);if (key == 27) {break;}}cv::destroyAllWindows();return 0;
}

編譯和運行

你需要根據你的 OpenCV 安裝方式來編譯代碼。

使用 GCC/G++ (Linux/macOS):

首先,確保你已經安裝了 pkg-config 并且 OpenCV 的 .pc 文件在它的搜索路徑中。

g++ your_file_name.cpp -o heart_rain $(pkg-config --cflags --libs opencv4)
# 如果你用的是OpenCV 3,可能是 opencv 而不是 opencv4
# g++ your_file_name.cpp -o heart_rain $(pkg-config --cflags --libs opencv)
./heart_rain

使用 CMake (推薦跨平臺):

創建一個 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.10)
project(HeartRain)set(CMAKE_CXX_STANDARD 11) # 或更高
set(CMAKE_CXX_STANDARD_REQUIRED True)find_package(OpenCV REQUIRED)include_directories(${OpenCV_INCLUDE_DIRS})add_executable(HeartRain your_file_name.cpp) # 替換 your_file_name.cpp
target_link_libraries(HeartRain ${OpenCV_LIBS})

然后編譯:

mkdir build
cd build
cmake ..
make
./HeartRain # 或者在Windows上是 .\Debug\HeartRain.exe

效果展示

運行程序后,你會看到一個窗口,其中有各種粉紅色或紅色的心形從頂部隨機落下,像下雨一樣。

(這里可以放一張最終效果的 GIF 或截圖)
(由于是文本格式,此處無法直接展示圖片)


進一步的改進

這個基礎版本可以有很多擴展:

  • 更精致的心形:使用貝塞爾曲線或導入 SVG 路徑來繪制更平滑的心形。
  • 旋轉:讓心形在下落時輕微旋轉。
  • 背景:添加一個漂亮的背景圖片而不是純黑色。
  • 風力效果:給心形增加水平方向的隨機漂移。
  • 性能優化:對于非常大量的對象,考慮更高效的渲染或對象管理。
  • 使用Alpha透明度:如果繪制的心形有重疊,可以考慮帶透明度的顏色。
  • 不同類型的心形:隨機生成幾種不同風格或圖案的心形。

總結

通過這個小項目,我們學習了如何使用 OpenCV 和 C++ 創建一個簡單的粒子動畫。我們涵蓋了對象的定義、繪制、隨機生成、狀態更新和動畫循環。希望你能從中獲得樂趣,并嘗試進行自己的修改和擴展!

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

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

相關文章

【記錄】Python|Python支持if 1<a<2、if not a、if a is None這三種寫法

今天讓AI幫我寫代碼&#xff0c;突然發現寫出來一句類似1<a<2&#xff0c;我頓感疑惑&#xff1a;不是只能用and連接嗎&#xff1f; 一試發現真行&#xff0c;那我辛辛苦苦寫了好幾年的 (條件1) and (條件2) 算什么&#xff1f;算我勤快嗎&#xff1f;&#x1f62d; 常…

Matlab | MATLAB 中的插值詳解

MATLAB 中的插值詳解 插值是數值分析中的核心技術,用于在已知數據點之間估計未知點的值。MATLAB 提供了完整的插值函數庫,涵蓋一維到高維數據,支持多種插值方法。以下從基礎到高級全面解析: 一、插值核心概念 1. 數學本質 給定數據點 ( x i , y i ) (x_i, y_i) (<

正則表達式檢測文件類型是否為視頻或圖片

// 配置化文件類型檢測&#xff08;集中管理支持的類型&#xff09; const FILE_TYPE_CONFIG {video: {extensions: [mp4, webm, ogg, quicktime], // 可擴展支持更多格式regex: /^video\/(mp4|webm|ogg|quicktime)$/i // 自動生成正則},image: {extensions: [jpeg, jpg, png,…

Redis最佳實踐——熱點數據緩存詳解

Redis在電商熱點數據緩存中的最佳實踐 一、熱點數據定義與識別 1. 熱點數據特征 高頻訪問&#xff08;QPS > 1000&#xff09;數據規模適中&#xff08;單條 < 10KB&#xff09;數據變化頻率低&#xff08;更新間隔 > 5分鐘&#xff09;業務關鍵性高&#xff08;直接…

8088單板機C語言sprintf()格式化串口輸出---Prj04

#include "tiny_stdarg.h" // 使用自定義可變參數實現#define ADR_273 0x0200 #define ADR_244 0x0400 #define LED_PORT 0x800 #define PC16550_THR 0x1f0 #define PC16550_LSR 0x1f5 / //基本的IO操作函數 / char str[]"Hello World! 20250531 Ve…

【面試】音視頻面試

H.264 與 H.265 有什么區別&#xff1f; 1&#xff09;主要區別 H.265 也稱為高效視頻編碼 (HEVC)&#xff0c;是 H.264 的升級和更高級的版本&#xff1b;H.265 的編碼架構大致上 和 H.264 的架構相似&#xff0c;主要也包含&#xff1a;幀內預測&#xff08;intra predicti…

Windows系統下npm報錯node-gyp configure got “gyp ERR“解決方法

感謝原博主&#xff0c;此文參考網址&#xff1a;https://zhuanlan.zhihu.com/p/398279220 確保已經安裝node.js &#xff08;官方網址&#xff1a;https://nodejs.org/zh-cn/download&#xff09; 首先在命令窗口執行命令安裝windows-build-tools&#xff1a; npm install -…

git stash命令用法

git stash 是 Git 中一個非常有用的命令&#xff0c;它可以臨時保存當前工作區的修改&#xff0c;讓你可以切換到其他分支或者處理其他任務&#xff0c;而不需要提交這些還未完成的修改。 一、基本用法 1. 保存當前修改&#xff08;包括暫存區和工作區的內容&#xff09; git…

【C語言練習】080. 使用C語言實現簡單的數據庫操作

080. 使用C語言實現簡單的數據庫操作 080. 使用C語言實現簡單的數據庫操作使用原生APIODBC接口第三方庫ORM框架文件模擬1. 安裝SQLite2. 示例代碼:使用SQLite創建數據庫、表和插入數據3. 編譯和運行4. 示例運行輸出:5. 注意事項6. 總結080. 使用C語言實現簡單的數據庫操作 在…

2025年目前最新版本Android Studio自定義xml預覽的屏幕分辨率

一、前言 在實際開發項目當中&#xff0c;我們的設備的分辨率可能會比較特殊&#xff0c;AS并沒有自帶這種屏幕分辨率的設備&#xff0c;但是我們又想一邊編寫XML界面&#xff0c;一邊實時看到較為真實的預覽效果&#xff0c;該怎么辦呢&#xff1f;在早期的AS版本中&#xff…

Edge Databases:賦能分布式計算環境

Edge 計算通過將數據處理推向數據源頭徹底改變了傳統計算范式。隨著物聯網設備、移動應用和分布式系統的大規模部署&#xff0c;面向邊緣場景優化的數據庫解決方案已成為關鍵技術需求。這類專用數據庫能夠在算力有限、內存受限且網絡連接不穩定的終端設備上穩定運行&#xff0c…

Pluto論文閱讀筆記

主要還是參考了這一篇論文筆記&#xff1a;https://zhuanlan.zhihu.com/p/18319150220 Pluto主要有三個創新點&#xff1a; 橫向縱向用lane的query來做將軌跡投回柵格化地圖&#xff0c;計算碰撞loss對數據進行正增強和負增強&#xff0c;讓正增強的結果也無增強的結果相近&a…

【計算機網絡】傳輸層UDP協議

&#x1f525;個人主頁&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收錄專欄&#x1f308;&#xff1a;計算機網絡 &#x1f339;往期回顧&#x1f339;&#xff1a; 【計算機網絡】應用層協議Http——構建Http服務服務器 &#x1f516;流水不爭&#xff0c;爭的是滔滔不…

「Java教案」順序結構

課程目標 1&#xff0e;知識目標 能夠正確使用Java順序結構的基本語法&#xff0c;例如變量的聲明、變量的賦值、表達式的計算、數據的輸出。能夠正確使用順序結構的執行規則及其在程序中的作用&#xff0c;解決實際問題。 2&#xff0e;能力目標 能夠獨立完成順序結構程序…

第八部分:階段項目 6:構建 React 前端應用

現在&#xff0c;是時候將你學到的 React 基礎知識付諸實踐&#xff0c;構建一個簡單的前端應用來模擬與后端 API 的交互了。在這個階段&#xff0c;你可以先使用模擬數據&#xff0c;或者如果你的后端 API&#xff08;階段項目 5&#xff09;已經搭建好&#xff0c;可以直接連…

GO語言----基礎類型取別名

文章目錄 取別名示例注意事項 Go語言中使用type關鍵字為基礎類型取別名。 type是Go語言中用于定義新類型的關鍵字&#xff0c;它提供了強大的類型定義能力。 取別名示例 type MyInt int注意事項 這創建了一個新類型MyInt&#xff0c;它底層是int類型&#xff0c;但與int是不同…

服務端定時器的學習(一)

一、定時器 1、定時器是什么&#xff1f; 定時器不僅存在于硬件領域&#xff0c;在軟件層面&#xff08;客戶端、網頁和服務端&#xff09;也普遍應用&#xff0c;核心功能都是高效管理大量延時任務。不同應用場景下&#xff0c;其實現方式和使用方法有所差異。 2、定時器解…

Mac版本Android Studio配置LeetCode插件

第一步&#xff1a;Android Studio里面找到Settings&#xff0c;找到Plugins&#xff0c;在Marketplace里面搜索LeetCode Editor。 第二步&#xff1a;安裝對應插件&#xff0c;并在Tools->LeetCode Plugin頁面輸入帳號和密碼。 理論上&#xff0c;應該就可以使用了。但是&a…

【ISP算法精粹】動手實戰:用 Python 實現 Bayer 圖像的黑電平校正

在數字成像領域&#xff0c;圖像信號處理器&#xff08;ISP&#xff09;如同幕后英雄&#xff0c;默默將傳感器捕獲的原始數據轉化為精美的圖像。而黑電平校正&#xff0c;作為ISP預處理流程中的關鍵一環&#xff0c;直接影響著最終圖像的質量。今天&#xff0c;我們就通過Pyth…

Oracle OCP與MySQL OCP認證如何選?

認證本質與定位差異 Oracle OCP Oracle OCP是Oracle公司推出的旗艦級數據庫專家認證&#xff0c;專注于其核心的閉源商業數據庫技術體系。核心領域包括RAC&#xff08;Real Application Clusters&#xff09;高可用集群、Data Guard容災解決方案、Exadata數據庫一體機集成以及…