OpenCV實(shí)現(xiàn)摳圖工具
本文實(shí)例為大家分享了OpenCV實(shí)現(xiàn)摳圖工具的具體代碼,供大家參考,具體內(nèi)容如下
在計(jì)算機(jī)圖像領(lǐng)域,我們經(jīng)常需要做一些摳圖的工作,將圖像中的目標(biāo)感興趣區(qū)域提取出來,剔除其他冗余的背景元素,以實(shí)現(xiàn)計(jì)算機(jī)視覺的各項(xiàng)功能(如車輛檢測(cè)、人臉檢測(cè)等)。如果純粹使用美圖秀秀等工具類軟件的話,由于工具類軟件將圖像處理中各種可能用到的功能都集成在了一起,所以純粹做摳圖的話效率很低。現(xiàn)在我們就用 OpenCV 來實(shí)現(xiàn)一段簡(jiǎn)易的摳圖程序,只需要在畫面上選定目標(biāo)的感興趣區(qū)域,該目標(biāo)就會(huì)被自動(dòng)按序號(hào)保存。
代碼如下,同時(shí)包含有通俗易懂的注釋:
#include <io.h> #include <conio.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <opencv.hpp> ? // 摳圖是單目標(biāo)還是多目標(biāo),若為單目標(biāo)請(qǐng)將下面這行文字取消注釋,反之請(qǐng)注釋這段文字。 // #define SINGLE_OBJECT ? #define TRUE 1? ? ?// 邏輯真 #define FALSE 0? ?// 邏輯假 ? #define CODE_ESC 27? ? ?// ESC 鍵的編碼 #define CODE_SPC 32? ? // 空格鍵的編碼 ? #define STATUS_WAIT 0? // 摳圖等待狀態(tài) #define STATUS_PROC 1? ? ?// 摳圖進(jìn)行狀態(tài) #define STATUS_DONE 2? ? // 摳圖完成狀態(tài) ? #define VIDEO_FILENAME "capture-1.mp4" ? ? ? ? ?// 視頻流文件名 ? static int m_x1 ? ? = 0;? ? // 鼠標(biāo)指針坐標(biāo)(起點(diǎn) x) static int m_x2 ? ? = 0;? ? // 鼠標(biāo)指針坐標(biāo)(終點(diǎn) x) static int m_y1 ? ? = 0;? ? // 鼠標(biāo)指針坐標(biāo)(起點(diǎn) y) static int m_y2 ? ? = 0;? ? ?// 鼠標(biāo)指針坐標(biāo)(終點(diǎn) y) static int m_status = STATUS_WAIT; ? ? ? ? ? ? ?// 當(dāng)前摳圖狀態(tài)指示 ? static void on_mouse(int, int, int, int, void*);// 鼠標(biāo)回調(diào) ? // 主程序 int main(void) { ?? ?int ? ? ? ?end ? ?= 0;? ? ? ? ?// 指示是否結(jié)束程序 ?? ?int ? ? ? ?next ? = 0;? ? ? ? ?// 指示是否切換到下一張圖片 ?? ?int ? ? ? ?code ? = 0;? ? ? ? // 存儲(chǔ)按鍵編碼 ?? ?int ? ? ? ?count ?= 0;? ? ? ? // 存儲(chǔ)目標(biāo)計(jì)數(shù) ?? ?int ? ? ? ?frame ?= 0;? ? ? ? ?// 視頻幀號(hào)(用于間隔采樣) ?? ?int ? ? ? ?maxCol = 0;? ? ? ? ? ? ?// 圖像最大列數(shù)(= 圖像寬度 - 1) ?? ?int ? ? ? ?maxRow = 0; ? ? ? ? ? ? ? ? ? ? ?// 圖像最大行數(shù)(= 圖像高度 - 1) ?? ?CvCapture* pVideo = NULL;? ? ? ? ? // 視頻流對(duì)象 ?? ?IplImage* ?pFrame = NULL;? ? ? ? ? ?// 視頻幀圖像(用于樣本存儲(chǔ)) ?? ?IplImage* ?pFrmCp = NULL;? ? ? ? ? ?// 視頻幀圖像(用于屏幕顯示) ?? ?CvPoint ? ?pt1 ? ?= cvPoint(0, 0); ? ? ? ? ?// 矩形框?qū)亲鴺?biāo)點(diǎn) 1 ?? ?CvPoint ? ?pt2 ? ?= cvPoint(0, 0); ? ? ? ? ?// 矩形框?qū)亲鴺?biāo)點(diǎn) 2 ?? ?CvRect ? ? r ? ? ?= cvRect(0, 0, 0, 0); ? ? // 感興趣區(qū)域矩形框 ?? ?char ? ? ? seq[] ?= "-2147483648"; ? ? ? ? ?// 目標(biāo)計(jì)數(shù)的字串形式 ?? ?char ? ? ? fil[] ?= "data\\-2147483648.jpg";// 文件名字串 ? ?? ?// 載入視頻流 ?? ?pVideo = cvCreateFileCapture(VIDEO_FILENAME); ?? ?if (!pVideo) ?? ?{ ?? ??? ?return -1; ?? ?} // if (!pVideo) ? ?? ?// 創(chuàng)建數(shù)據(jù)存儲(chǔ)目錄 ?? ?if (_access("data", 0) != 0) ?? ?{ ?? ??? ?system("md data"); ?? ?} // if (_access()) ? ?? ?// 獲取首幀圖像,并創(chuàng)建拷貝,同時(shí)得到最大列數(shù)和行數(shù),方便之后使用 ?? ?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 ? ?? ?// 設(shè)置顯示窗口,并設(shè)置鼠標(biāo)回調(diào) ?? ?cvNamedWindow("Monitor", CV_WINDOW_AUTOSIZE); ?? ?cvSetMouseCallback("Monitor", on_mouse, NULL); ? ?? ?// 其他初始化 ?? ?end = FALSE; ?? ?count = 0; ?? ?frame = 0; ? ?? ?while (!end && pFrame) ?? ?{ ?? ??? ?next = FALSE; ?? ??? ?while (!next && !end) ?? ??? ?{ ?? ??? ??? ?// 將原始視頻圖像復(fù)制到拷貝區(qū)域中(清除已將圖像進(jìn)行污染的線條、矩形框等) ?? ??? ??? ?cvCopy(pFrame, pFrmCp, NULL); ?? ??? ??? ?if (STATUS_WAIT == m_status) ?? ??? ??? ?{ ?? ??? ??? ??? ?// 等待摳圖狀態(tài)。畫出橫向和縱向的參考線 ?? ??? ??? ??? ?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) ?? ??? ??? ?{ ?? ??? ??? ??? ?// 摳圖過程中。畫出當(dāng)前選定的感興趣區(qū)域 ?? ??? ??? ??? ?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) ?? ??? ??? ?{ ?? ??? ??? ??? ?// 摳圖完畢,獲得感興趣區(qū)域并按編號(hào)保存樣本 ?? ??? ??? ??? ?r = cvRect( ?? ??? ??? ??? ??? ?m_x1, ?? ??? ??? ??? ??? ?m_y1, ?? ??? ??? ??? ??? ?m_x2 - m_x1 + 1, ?? ??? ??? ??? ??? ?m_y2 - m_y1 + 1 ?? ??? ??? ??? ??? ?); // 矩形感興趣區(qū)域 ?? ??? ??? ??? ?if (r.width > 30 && r.height > 30) ?? ??? ??? ??? ?{ ?? ??? ??? ??? ??? ?// 區(qū)域達(dá)到了一定大小,摳圖有效,保存感興趣區(qū)域樣本 ?? ??? ??? ??? ??? ?++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) ?? ??? ??? ??? ? ?? ??? ??? ??? ?// 恢復(fù)摳圖等待狀態(tài) ?? ??? ??? ??? ?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() ? ? // 鼠標(biāo)事件回調(diào) void on_mouse(int event, int x, int y, int flags, void* param) { ?? ?switch (flags) ?? ?{ ?? ?case CV_EVENT_MOUSEMOVE: ?? ??? ?if (STATUS_WAIT == m_status) ?? ??? ?{ ?? ??? ??? ?// 等待狀態(tài),確定感興趣區(qū)域起點(diǎn) ?? ??? ??? ?m_x1 = x, m_y1 = y; ?? ??? ?} // if (STATUS_WAIT) ?? ??? ?else if (STATUS_PROC == m_status) ?? ??? ?{ ?? ??? ??? ?// 捕捉狀態(tài),確定感興趣區(qū)域終點(diǎn) ?? ??? ??? ?m_x2 = x, m_y2 = y; ?? ??? ?} // else if (STATUS_PROC) ?? ??? ?break; ? ?? ?case CV_EVENT_LBUTTONDOWN: ?? ??? ?if (STATUS_WAIT == m_status) ?? ??? ?{ ?? ??? ??? ?// 等待狀態(tài)按下鼠標(biāo),進(jìn)入捕捉狀態(tài),固定起點(diǎn) ?? ??? ??? ?m_x1 = x, m_y1 = y; ?? ??? ??? ?m_status = STATUS_PROC; ?? ??? ?} // if (STATUS_WAIT) ?? ??? ?else if (STATUS_PROC == m_status) ?? ??? ?{ ?? ??? ??? ?// 捕捉狀態(tài)按下鼠標(biāo),捕捉完成,固定終點(diǎn) ?? ??? ??? ?m_x2 = x, m_y2 = y; ?? ??? ??? ?m_status = STATUS_DONE; ?? ??? ?} // else if (STATUS_PROC) ?? ??? ?break; ?? ?} // switch } // on_mouse()
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C語言編程C++動(dòng)態(tài)內(nèi)存分配示例講解
這篇文章主要介紹了C語言編程C++動(dòng)態(tài)內(nèi)存分配示例講解,為什么存在動(dòng)態(tài)內(nèi)存分配?本文通過動(dòng)態(tài)內(nèi)存介紹及常見內(nèi)存錯(cuò)誤等示例來為大家講解2021-09-09詳談C與C++的函數(shù)聲明中省略參數(shù)的不同意義
下面小編就為大家分享一篇詳談C與C++的函數(shù)聲明中省略參數(shù)的不同意義,具有非常好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-11-11C++數(shù)據(jù)結(jié)構(gòu)關(guān)于棧迷宮求解示例
這篇文章主要為大家介紹了C++數(shù)據(jù)結(jié)構(gòu)關(guān)于棧的迷宮求解示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2021-11-11C++實(shí)現(xiàn)循環(huán)隊(duì)列
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)循環(huán)隊(duì)列,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-01-01C++實(shí)現(xiàn)LeetCode(34.在有序數(shù)組中查找元素的第一個(gè)和最后一個(gè)位置)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(34.在有序數(shù)組中查找元素的第一個(gè)和最后一個(gè)位置),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07opencv3/C++關(guān)于移動(dòng)對(duì)象的輪廓的跟蹤詳解
今天小編就為大家分享一篇opencv3/C++關(guān)于移動(dòng)對(duì)象的輪廓的跟蹤詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-12-12