OpenCV实现抠图工具

OpenCV实现抠图工具

本文实例为大家分享了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.webp";// 文件名字串     // 载入视频流     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, ".webp");                     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()

推荐阅读