網站首頁 編程語言 正文
本文實例為大家分享了OpenCV實現摳圖工具的具體代碼,供大家參考,具體內容如下
在計算機圖像領域,我們經常需要做一些摳圖的工作,將圖像中的目標感興趣區域提取出來,剔除其他冗余的背景元素,以實現計算機視覺的各項功能(如車輛檢測、人臉檢測等)。如果純粹使用美圖秀秀等工具類軟件的話,由于工具類軟件將圖像處理中各種可能用到的功能都集成在了一起,所以純粹做摳圖的話效率很低。現在我們就用 OpenCV 來實現一段簡易的摳圖程序,只需要在畫面上選定目標的感興趣區域,該目標就會被自動按序號保存。
代碼如下,同時包含有通俗易懂的注釋:
#include <io.h> #include <conio.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <opencv.hpp> ? // 摳圖是單目標還是多目標,若為單目標請將下面這行文字取消注釋,反之請注釋這段文字。 // #define SINGLE_OBJECT ? #define TRUE 1? ? ?// 邏輯真 #define FALSE 0? ?// 邏輯假 ? #define CODE_ESC 27? ? ?// ESC 鍵的編碼 #define CODE_SPC 32? ? // 空格鍵的編碼 ? #define STATUS_WAIT 0? // 摳圖等待狀態 #define STATUS_PROC 1? ? ?// 摳圖進行狀態 #define STATUS_DONE 2? ? // 摳圖完成狀態 ? #define VIDEO_FILENAME "capture-1.mp4" ? ? ? ? ?// 視頻流文件名 ? static int m_x1 ? ? = 0;? ? // 鼠標指針坐標(起點 x) static int m_x2 ? ? = 0;? ? // 鼠標指針坐標(終點 x) static int m_y1 ? ? = 0;? ? // 鼠標指針坐標(起點 y) static int m_y2 ? ? = 0;? ? ?// 鼠標指針坐標(終點 y) static int m_status = STATUS_WAIT; ? ? ? ? ? ? ?// 當前摳圖狀態指示 ? static void on_mouse(int, int, int, int, void*);// 鼠標回調 ? // 主程序 int main(void) { ?? ?int ? ? ? ?end ? ?= 0;? ? ? ? ?// 指示是否結束程序 ?? ?int ? ? ? ?next ? = 0;? ? ? ? ?// 指示是否切換到下一張圖片 ?? ?int ? ? ? ?code ? = 0;? ? ? ? // 存儲按鍵編碼 ?? ?int ? ? ? ?count ?= 0;? ? ? ? // 存儲目標計數 ?? ?int ? ? ? ?frame ?= 0;? ? ? ? ?// 視頻幀號(用于間隔采樣) ?? ?int ? ? ? ?maxCol = 0;? ? ? ? ? ? ?// 圖像最大列數(= 圖像寬度 - 1) ?? ?int ? ? ? ?maxRow = 0; ? ? ? ? ? ? ? ? ? ? ?// 圖像最大行數(= 圖像高度 - 1) ?? ?CvCapture* pVideo = NULL;? ? ? ? ? // 視頻流對象 ?? ?IplImage* ?pFrame = NULL;? ? ? ? ? ?// 視頻幀圖像(用于樣本存儲) ?? ?IplImage* ?pFrmCp = NULL;? ? ? ? ? ?// 視頻幀圖像(用于屏幕顯示) ?? ?CvPoint ? ?pt1 ? ?= cvPoint(0, 0); ? ? ? ? ?// 矩形框對角坐標點 1 ?? ?CvPoint ? ?pt2 ? ?= cvPoint(0, 0); ? ? ? ? ?// 矩形框對角坐標點 2 ?? ?CvRect ? ? r ? ? ?= cvRect(0, 0, 0, 0); ? ? // 感興趣區域矩形框 ?? ?char ? ? ? seq[] ?= "-2147483648"; ? ? ? ? ?// 目標計數的字串形式 ?? ?char ? ? ? fil[] ?= "data\\-2147483648.jpg";// 文件名字串 ? ?? ?// 載入視頻流 ?? ?pVideo = cvCreateFileCapture(VIDEO_FILENAME); ?? ?if (!pVideo) ?? ?{ ?? ??? ?return -1; ?? ?} // if (!pVideo) ? ?? ?// 創建數據存儲目錄 ?? ?if (_access("data", 0) != 0) ?? ?{ ?? ??? ?system("md data"); ?? ?} // if (_access()) ? ?? ?// 獲取首幀圖像,并創建拷貝,同時得到最大列數和行數,方便之后使用 ?? ?pFrame = cvQueryFrame(pVideo); ?? ?if (pFrame) ?? ?{ ?? ??? ?pFrmCp = cvCreateImage(cvGetSize(pFrame), 8, pFrame->nChannels); ?? ??? ?maxCol = pFrmCp->width - 1; ?? ??? ?maxRow = pFrmCp->height - 1; ?? ?} // if (pFrame) ?? ?else ?? ?{ ?? ??? ?cvReleaseCapture(&pVideo); ?? ??? ?return -1; ?? ?} // else ? ?? ?// 設置顯示窗口,并設置鼠標回調 ?? ?cvNamedWindow("Monitor", CV_WINDOW_AUTOSIZE); ?? ?cvSetMouseCallback("Monitor", on_mouse, NULL); ? ?? ?// 其他初始化 ?? ?end = FALSE; ?? ?count = 0; ?? ?frame = 0; ? ?? ?while (!end && pFrame) ?? ?{ ?? ??? ?next = FALSE; ?? ??? ?while (!next && !end) ?? ??? ?{ ?? ??? ??? ?// 將原始視頻圖像復制到拷貝區域中(清除已將圖像進行污染的線條、矩形框等) ?? ??? ??? ?cvCopy(pFrame, pFrmCp, NULL); ?? ??? ??? ?if (STATUS_WAIT == m_status) ?? ??? ??? ?{ ?? ??? ??? ??? ?// 等待摳圖狀態。畫出橫向和縱向的參考線 ?? ??? ??? ??? ?cvLine(pFrmCp, cvPoint(m_x1, 0), cvPoint(m_x1, maxRow), CV_RGB(0, 255, 0)); ?? ??? ??? ??? ?cvLine(pFrmCp, cvPoint(0, m_y1), cvPoint(maxCol, m_y1), CV_RGB(0, 255, 0)); ?? ??? ??? ?} // if (STATUS_WAIT) ?? ??? ??? ?else if (STATUS_PROC == m_status) ?? ??? ??? ?{ ?? ??? ??? ??? ?// 摳圖過程中。畫出當前選定的感興趣區域 ?? ??? ??? ??? ?pt1 = cvPoint(m_x1, m_y1); ?? ??? ??? ??? ?pt2 = cvPoint(m_x2, m_y2); ?? ??? ??? ??? ?cvRectangle(pFrmCp, pt1, pt2, CV_RGB(0, 255, 0)); ?? ??? ??? ?} // else if (STATUS_PROC) ?? ??? ??? ?else if (STATUS_DONE == m_status) ?? ??? ??? ?{ ?? ??? ??? ??? ?// 摳圖完畢,獲得感興趣區域并按編號保存樣本 ?? ??? ??? ??? ?r = cvRect( ?? ??? ??? ??? ??? ?m_x1, ?? ??? ??? ??? ??? ?m_y1, ?? ??? ??? ??? ??? ?m_x2 - m_x1 + 1, ?? ??? ??? ??? ??? ?m_y2 - m_y1 + 1 ?? ??? ??? ??? ??? ?); // 矩形感興趣區域 ?? ??? ??? ??? ?if (r.width > 30 && r.height > 30) ?? ??? ??? ??? ?{ ?? ??? ??? ??? ??? ?// 區域達到了一定大小,摳圖有效,保存感興趣區域樣本 ?? ??? ??? ??? ??? ?++count; ?? ??? ??? ??? ??? ?cvSetImageROI ? (pFrame, r); ?? ??? ??? ??? ??? ?sprintf_s ? ? ? (seq, "%d", count); ?? ??? ??? ??? ??? ?strcpy_s ? ? ? ?(fil, "data\\"); ?? ??? ??? ??? ??? ?strcat_s ? ? ? ?(fil, seq); ?? ??? ??? ??? ??? ?strcat_s ? ? ? ?(fil, ".jpg"); ?? ??? ??? ??? ??? ?cvSaveImage ? ? (fil, pFrame, 0); ?? ??? ??? ??? ??? ?cvResetImageROI (pFrame); ? #ifdef SINGLE_OBJECT ?? ??? ??? ??? ??? ?m_next = TRUE; #endif ?? ??? ??? ??? ?} // if (r.width) ?? ??? ??? ??? ? ?? ??? ??? ??? ?// 恢復摳圖等待狀態 ?? ??? ??? ??? ?m_status = STATUS_WAIT; ?? ??? ??? ?} // else if (STATUS_DONE) ? ?? ??? ??? ?cvShowImage("Monitor", pFrmCp); ?? ??? ??? ?code = cvWaitKey(10); ?? ??? ??? ?if (CODE_SPC == code) ?? ??? ??? ?{ ?? ??? ??? ??? ?next = TRUE; ?? ??? ??? ?} // if (CODE_SPC) ?? ??? ??? ?else if (CODE_ESC == code) ?? ??? ??? ?{ ?? ??? ??? ??? ?end = TRUE; ?? ??? ??? ?} // else if (CODE_ESC) ?? ??? ?} // while (!next) ? ?? ??? ?if (next) ?? ??? ?{ ?? ??? ??? ?do ?? ??? ??? ?{ ?? ??? ??? ??? ?pFrame = cvQueryFrame(pVideo); ?? ??? ??? ??? ?++frame; ?? ??? ??? ?} while (pFrame && frame % 60 != 0); // do...while ?? ??? ?} // if (next) ?? ?} // while (!end) ? ?? ?cvDestroyAllWindows(); ?? ?cvReleaseImage(&pFrmCp); ?? ?cvReleaseCapture(&pVideo); ? ?? ?return 0; } // main() ? ? // 鼠標事件回調 void on_mouse(int event, int x, int y, int flags, void* param) { ?? ?switch (flags) ?? ?{ ?? ?case CV_EVENT_MOUSEMOVE: ?? ??? ?if (STATUS_WAIT == m_status) ?? ??? ?{ ?? ??? ??? ?// 等待狀態,確定感興趣區域起點 ?? ??? ??? ?m_x1 = x, m_y1 = y; ?? ??? ?} // if (STATUS_WAIT) ?? ??? ?else if (STATUS_PROC == m_status) ?? ??? ?{ ?? ??? ??? ?// 捕捉狀態,確定感興趣區域終點 ?? ??? ??? ?m_x2 = x, m_y2 = y; ?? ??? ?} // else if (STATUS_PROC) ?? ??? ?break; ? ?? ?case CV_EVENT_LBUTTONDOWN: ?? ??? ?if (STATUS_WAIT == m_status) ?? ??? ?{ ?? ??? ??? ?// 等待狀態按下鼠標,進入捕捉狀態,固定起點 ?? ??? ??? ?m_x1 = x, m_y1 = y; ?? ??? ??? ?m_status = STATUS_PROC; ?? ??? ?} // if (STATUS_WAIT) ?? ??? ?else if (STATUS_PROC == m_status) ?? ??? ?{ ?? ??? ??? ?// 捕捉狀態按下鼠標,捕捉完成,固定終點 ?? ??? ??? ?m_x2 = x, m_y2 = y; ?? ??? ??? ?m_status = STATUS_DONE; ?? ??? ?} // else if (STATUS_PROC) ?? ??? ?break; ?? ?} // switch } // on_mouse()
原文鏈接:https://blog.csdn.net/smallyang0613/article/details/49072783
相關推薦
- 2022-04-28 C++Stack棧類模版實例詳解_C 語言
- 2023-01-02 Android?數據結構全面總結分析_Android
- 2023-05-05 Linux中grep命令詳解_linux shell
- 2022-03-14 關于跨域 Response to preflight request doesn‘t pass ac
- 2023-02-04 Rust?語言的全鏈路追蹤庫?tracing使用方法_Rust語言
- 2023-02-14 Android?SharedPreference存儲文件三步走_Android
- 2022-11-09 PostgreSQL索引掃描時為什么index?only?scan不返回ctid_PostgreSQ
- 2022-12-08 Python中的pandas庫簡介及其使用教程_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支