有關opencv的學習(19)—GrabCut算法提取前景物體

    

      OpenCV中的GrabCut算法是Graphcut算法的改進, Grabcut是一種直接基於圖割算法的圖像分割技術, 僅僅需要確認前景和背景輸入, 該算法就可以完成前景和背景的最優分割, 算法依據《“GrabCut” - Interactive Foreground Extraction using Iterated Graph Cuts》這篇文章來實現的。該算法利用了圖像中的紋理(顏色)信息和邊界(反差)信息, 只要少量的用戶交互操作即可得到比較好的分割結果, 和分水嶺算法比較相似, 但是計算速度比較慢, 得到的結果比較精確。如果要從靜態圖像中提取前景物體(如從一個圖像剪切物體到另一個圖像), 採用GrabCut算法是最好的選擇。

    用法很簡單: 只需輸入一幅圖像, 並對一些像素做屬於背景或屬於前景的標記, 算法會根據這個局部標記, 計算出整個圖像中前景和背景的分割線。

如下:

CV_EXPORTS_Wvoid grabCut(InputArray img, 

                                                      InputOutputArray mask, 

           Rect rect,

                                                     InputOutputArray bgdModel, 

                                                      InputOutputArray fgdModel,

                                                     int iterCount,  

                                                      int mode =GC_EVAL );

img: 待分割原圖像,需爲8位三通道彩色圖像

mask: 8位單通道掩碼圖像, 如果使用掩碼進行初始化, 那麼mask保存掩碼信息, 在執行分割的時候, 也可以將用戶交互所設定的前景與背景保存到mask中,然後再傳入grabCut函數, 在處理結束之後,mask中會保存結果。Mask只能取4種可能的值:

   cv::GC_BGD: 表示明確屬於背景的像素;

   cv::GC_FGD: 表示明確屬於前景的像素;

   cv::GC_PR_BGD: 表示可能屬於背景的像素;

   cv::GC_PR_FGD: 表示可能屬於前景的像素;

   cv::GC_FGD,cv::GC_PR_FGD定義的值爲1和3,cv::GC_BGD,cv::GC_PR_BGD定義爲0和2.


   如果沒有手動標記GC_BGD或者GC_FGD, 那麼結果只會有GC_PR_BGD或GC_PR_FGD;

rect: 包含分割對象的矩形ROI, 矩形外部的像素爲背景, 矩形內部的像素爲前景,當參數mode=GC_INIT_WITH_RECT使用;

bgdModel: 背景模型(內部使用);

fgdModel: 前景模型(內部使用);

iterCount: 迭代次數, 必須大於0;

mode: 用於指示grabCut函數進行什麼操作, 可選的值有:

    GC_INIT_WITH_RECT:用矩形框初始化GrabCut

   GC_INIT_WITH_MASK:用掩碼圖像初始化GrabCut

    GC_EVAL:執行分割

所用圖像如下所示:


opencv中在圖片上畫矩形框的程序如下所示:

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>


using namespace cv;
using namespace std;


int main()
{
        
    Mat image=imread("/Users/zhangxiaoyu/Desktop/3.png");
    if(image.empty())
    {
        cout<<"Error!/n";
        return -1;
    }
        
    rectangle(image, Point(160,70), Point(400,490), cv::Scalar(255,0,0));
    cv::imshow("result", image);
    
    
    waitKey(0);
    
}

使用grabCut算法後,結果如下圖所示:


代碼如下所示:

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;


int main()
{
    Mat image=imread("/Users/zhangxiaoyu/Desktop/3.png");
    if(image.empty())
    {   cout<<"Error!/n";
        return -1;
}
    

    cv::Mat bg;//模型(內部使用)
    cv::Mat fg;
    
    Rect rect = Rect(47,48,408,464);//矩形區域
    
    cv::Mat result;//結果
    result.create(image.size(), CV_8UC3);
    cv::Mat foreground;//前景
    foreground.create(image.size(), CV_8UC3);
    
    cv::grabCut(image, foreground, rect, bg, fg, 5,cv::GC_INIT_WITH_RECT);
    
    //用按位與運算檢查第一位
    foreground = foreground & 1;//如果是前景像素,結果爲1
    image.copyTo(result,foreground);
    
    imshow("image",result);

    waitKey(0);
    return 0;
    
}

       GrabCut算法用以下步驟進行背景/前景分割。首先,把所有未標記的像素臨時標爲前景(cv::GC_PR_FGD)。基於

當前的分類情況,算法把像素劃分爲多個顏色相似的組(即K個背景組和K個前景組)。下一步是通過引入前景和背景像素之間的邊緣,來確定背景/前景的分割。這將通過一個優化過程來實現,過程中試圖連接具有相似標記的像素,並且避免在強度相對一致的區域上放置邊緣。

      因此,GrabCut算法是一個逐步改進分割結果的迭代過程。根據場景的複雜程度,找到最佳方案所需的迭代次數各不相同(對於簡單的情況,迭代一次就足夠了)。














發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章