1. 程式人生 > >OpenCVForUnity 影象分割,分離前景和背景

OpenCVForUnity 影象分割,分離前景和背景

實現效果:


主要用到的方法是 grabCut方法。

目前網上沒有找到關於OpenCVForUnity的文件,磕磕絆絆的看著網上較多的opencv c++程式碼參考實現的,成功實現背景分離的時候感覺還是很美好的,記錄下。

首先是關於這方法的說明:

GrabCut函式說明

void grabCut(InputArray img, InputOutputArray mask, Rect rect, InputOutputArraybgdModel, InputOutputArrayfgdModel, intiterCount, intmode=GC_EVAL)

Parameters:
  • image – Input 8-bit 3-channel image.
  • mask –

    Input/output 8-bit single-channel mask. The mask is initialized by the function whenmode is set to GC_INIT_WITH_RECT. Its elements may have one of following values:

    • GC_BGD defines an obvious background pixels.
    • GC_FGD defines an obvious foreground (object) pixel.
    • GC_PR_BGD defines a possible background pixel.
    • GC_PR_BGD defines a possible foreground pixel.
  • rect – ROI containing a segmented object. The pixels outside of the ROI are marked as “obvious background”. The parameter is only used whenmode==GC_INIT_WITH_RECT .
  • bgdModel – Temporary array for the background model. Do not modify it while you are processing the same image.
  • fgdModel – Temporary arrays for the foreground model. Do not modify it while you are processing the same image.
  • iterCount – Number of iterations the algorithm should make before returning the result. Note that the result can be refined with further calls withmode==GC_INIT_WITH_MASK ormode==GC_EVAL .
  • mode –

    Operation mode that could be one of the following:

    • GC_INIT_WITH_RECT The function initializes the state and the mask using the provided rectangle. After that it runsiterCountiterations of the algorithm.
    • GC_INIT_WITH_MASK The function initializes the state using the provided mask. Note thatGC_INIT_WITH_RECT andGC_INIT_WITH_MASK can be combined. Then, all the pixels outside of the ROI are automatically initialized withGC_BGD .
    • GC_EVAL The value means that the algorithm should just resume.

函式原型:
    void cv::grabCut( const Mat& img, Mat& mask, Rect rect,
             Mat& bgdModel, Mat& fgdModel,
             int iterCount, int mode )
其中:
img——待分割的源影象,必須是8位3通道(CV_8UC3)影象,在處理的過程中不會被修改;
mask——掩碼影象,如果使用掩碼進行初始化,那麼mask儲存初始化掩碼資訊;在執行分割的時候,也可以將使用者互動所設定的前景與背景儲存到mask中,然後再傳入grabCut函式;在處理結束之後,mask中會儲存結果。mask只能取以下四種值:
GCD_BGD(=0),背景;
GCD_FGD(=1),前景;
GCD_PR_BGD(=2),可能的背景;
GCD_PR_FGD(=3),可能的前景。
如果沒有手工標記GCD_BGD或者GCD_FGD,那麼結果只會有GCD_PR_BGD或GCD_PR_FGD;
rect——用於限定需要進行分割的影象範圍,只有該矩形視窗內的影象部分才被處理;
bgdModel——背景模型,如果為null,函式內部會自動建立一個bgdModel;bgdModel必須是單通道浮點型(CV_32FC1)影象,且行數只能為1,列數只能為13x5;
fgdModel——前景模型,如果為null,函式內部會自動建立一個fgdModel;fgdModel必須是單通道浮點型(CV_32FC1)影象,且行數只能為1,列數只能為13x5;
iterCount——迭代次數,必須大於0;
mode——用於指示grabCut函式進行什麼操作,可選的值有:
GC_INIT_WITH_RECT(=0),用矩形窗初始化GrabCut;
GC_INIT_WITH_MASK(=1),用掩碼影象初始化GrabCut;
GC_EVAL(=2),執行分割。

具體程式碼:

using UnityEngine;
using OpenCVForUnity;

public class TextureCutOut : MonoBehaviour {
    private Mat image ;
    private Mat mask, binMask, dstMat;
    private OpenCVForUnity.Rect rect;
    private Mat bgModel, fgModel;
    byte[] maskPixels;
    // Use this for initialization
    void Start () {
        Texture2D inputTexture = Resources.Load("inputTexture") as Texture2D;
        image = new Mat(inputTexture.height, inputTexture.width, CvType.CV_8UC3);
        Utils.texture2DToMat(inputTexture, image);
        mask = new Mat(inputTexture.height, inputTexture.width, CvType.CV_8UC1);
        mask.setTo(new Scalar(Imgproc.GC_BGD));

        rect = new OpenCVForUnity.Rect(45,25, 175, 210);

        //掩碼空間mask對應矩形空間內的掩碼設定為GC_PR_FGD(預設為前景)
        Mat matRectCol = mask.colRange(rect.x, rect.x + rect.width);
        Mat matRectRow = mask.rowRange(rect.y, rect.y + rect.height);
        matRectCol.setTo(new Scalar(Imgproc.GC_PR_FGD));
        matRectRow.setTo(new Scalar(Imgproc.GC_PR_FGD));

        //框出預設前景
        Imgproc.rectangle(image,new Point(rect.x, rect.y),new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 0, 255, 255), 2);
        //Texture2D outputTexture = new Texture2D(image.cols(), image.rows(), TextureFormat.RGBA32, false);
        //Utils.matToTexture2D(image, outputTexture);

        //重新讀取原始圖片 切割
        Utils.texture2DToMat(inputTexture, image);
        bgModel = new Mat();
        fgModel = new Mat();
        Imgproc.grabCut(image, mask, rect, bgModel, fgModel, 1);
        GetBinMask(ref mask, ref binMask);
        dstMat = new Mat(mask.size(), CvType.CV_8UC1);
        image.copyTo(dstMat, binMask);

        Texture2D outputTexture = new Texture2D(dstMat.cols(), dstMat.rows(), TextureFormat.RGBA32, false);
        Utils.matToTexture2D(dstMat, outputTexture);

        gameObject.GetComponent<Renderer>().material.mainTexture = outputTexture;
    }
	
	// Update is called once per frame
	void Update () {
	}

    void GetBinMask(ref Mat comMask,ref Mat binMask)
    {
        binMask = new Mat(comMask.size(), CvType.CV_8UC1);
        //commask中有0,1,2,3四種取值,這句就是取值為0,2的在binmask都為0,取值1,3的在binmask中為1
        //binMask = comMask & 1;
        maskPixels = new byte[comMask.cols() * comMask.rows()*comMask.channels()];
        comMask.get(0,0,maskPixels);
        for (int i = 0; i < maskPixels.Length; i++)
        {
            if (maskPixels[i] == 0 || maskPixels[i] == 2)
            {
                maskPixels[i] = 0;
            }
            if (maskPixels[i] == 1 || maskPixels[i] == 3)
            {
                maskPixels[i] = 1;
            }
        }
        binMask.put(0,0, maskPixels);
    }
}

20170912更新:

原先的切割後背景是黑色,根據專案需求要變成透明的,試驗了多次,OpenCVForUnity自帶的copyTo()方法沒有實現,就自己寫了一個帶遮罩的圖片疊加方法,效果如下:


程式碼:

using UnityEngine;
using OpenCVForUnity;

public class TextureCutOut : MonoBehaviour {
    private Mat image ;
    private Mat mask, binMask, dstMat,tranparentMat;
    private OpenCVForUnity.Rect rect;
    private Mat bgModel, fgModel;
    byte[] maskPixels;
    byte[] srcPixels;
    byte[] dstPixels;
    // Use this for initialization
    void Start () {
        Texture2D inputTexture = Resources.Load("1") as Texture2D;
        image = new Mat(inputTexture.height, inputTexture.width, CvType.CV_8UC3);
        Utils.texture2DToMat(inputTexture, image);
        mask = new Mat(inputTexture.height, inputTexture.width, CvType.CV_8UC1);
        mask.setTo(new Scalar(Imgproc.GC_BGD));

        rect = new OpenCVForUnity.Rect(30,50, 450, 900);

        //掩碼空間mask對應矩形空間內的掩碼設定為GC_PR_FGD(預設為前景)
        Mat matRectCol = mask.colRange(rect.x, rect.x + rect.width);
        Mat matRectRow = mask.rowRange( rect.y, rect.y + rect.height);
        matRectCol.setTo(new Scalar(Imgproc.GC_PR_FGD));
        matRectRow.setTo(new Scalar(Imgproc.GC_PR_FGD));

        //框出預設前景
        Imgproc.rectangle(image,new Point(rect.x, rect.y),new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 0, 255, 255), 2);
        //Texture2D outputTexture = new Texture2D(image.cols(), image.rows(), TextureFormat.RGBA32, false);
        //Utils.matToTexture2D(image, outputTexture);

        //重新讀取原始圖片 切割
        Utils.texture2DToMat(inputTexture, image);
        bgModel = new Mat();
        fgModel = new Mat();
        Imgproc.grabCut(image, mask, rect, bgModel, fgModel, 1);
        GetBinMask(ref mask, ref binMask);
        

        dstMat = new Mat(mask.size(), CvType.CV_8UC4);
        //自己寫的圖片疊加函式,實現背景部分透明
        MyCopt(ref image, ref dstMat, ref binMask);

        //自帶的帶掩碼複製方法,背景部分是黑色
        //image.copyTo(dstMat, binMask);
        //SetBlackPixelTranspalent(ref dstMat);

        Texture2D outputTexture = new Texture2D(dstMat.cols(), dstMat.rows(), TextureFormat.RGBA32, false);
        Utils.matToTexture2D(dstMat, outputTexture);

        gameObject.GetComponent<Renderer>().material.mainTexture = outputTexture;
    }
	
	// Update is called once per frame
	void Update () {
	}

    void GetBinMask(ref Mat comMask,ref Mat binMask)
    {
        binMask = new Mat(comMask.size(), CvType.CV_8UC1);
        //commask中有0,1,2,3四種取值,這句就是取值為0,2的在binmask都為0,取值1,3的在binmask中為1;
        //值為 0為背景,1為前景
        //binMask = comMask & 1;
        maskPixels = new byte[comMask.cols() * comMask.rows()*comMask.channels()];
        comMask.get(0,0,maskPixels);
        for (int i = 0; i < maskPixels.Length; i++)
        {
            if (maskPixels[i] == 0 || maskPixels[i] == 2)
            {
                maskPixels[i] = 0;
            }
            if (maskPixels[i] == 1 || maskPixels[i] == 3)
            {
                maskPixels[i] = 1;
            }
        }
        binMask.put(0,0, maskPixels);
    }

    //把圖片中黑色部分變透明
    void SetBlackPixelTranspalent(ref Mat mask)
    {
        Imgproc.cvtColor(mask, mask, Imgproc.COLOR_BGR2BGRA);
        srcPixels = new byte[mask.cols() * mask.rows() * mask.channels()];
        mask.get(0, 0, srcPixels);
        byte b;
        byte g;
        byte r;
        for (int i = 0; i < srcPixels.Length; i += 4)
        {
            b = srcPixels[i];
            g = srcPixels[i + 1];
            r = srcPixels[i + 2];
            if (b == 0 && g == 0 && r == 0)
            {
                srcPixels[i + 3] = 0;
            }
            else
                srcPixels[i + 3] = 255;
        }
        mask.put(0,0, srcPixels);
    }

    void MyCopt(ref Mat srcMat,ref Mat dstMat,ref Mat mask)
    {
        maskPixels = new byte[mask.cols() * mask.rows() * mask.channels()];
        srcPixels = new byte[srcMat.cols() * srcMat.rows() * srcMat.channels()];
        dstPixels = new byte[dstMat.cols() * dstMat.rows() * dstMat.channels()];
        int n1 = mask.channels();
        int n2 = srcMat.channels();
        int n3 = dstMat.channels();
        
        mask.get(0,0,maskPixels);
        srcMat.get(0,0,srcPixels);
        dstMat.get(0,0,dstPixels);
        for (int i = 0; i < maskPixels.Length; i++)
        {
            if (maskPixels[i] == 1)
            {
                dstPixels[i * 4 + 0] = srcPixels[i * 3 + 0];
                dstPixels[i * 4 + 1] = srcPixels[i * 3 + 1];
                dstPixels[i * 4 + 2] = srcPixels[i * 3 + 2];
                dstPixels[i * 4 + 3] = 255;
            }
        }
        dstMat.put(0,0,dstPixels);
    }
}

相關推薦

OpenCVForUnity 影象分割分離前景背景

實現效果: 主要用到的方法是 grabCut方法。 目前網上沒有找到關於OpenCVForUnity的文件,磕磕絆絆的看著網上較多的opencv c++程式碼參考實現的,成功實現背景分離的時候感覺還是很美好的,記錄下。 首先是關於這方法的說明: GrabCut函式說明

opencv實現影象分割分離前景背景(1)

簡介   如題,本篇就是講解和使用opencv函式grabcut,來實現影象前景與背景的分離。 函式原型   1、opencv官方介紹:opencv官方grabcut介紹   2、網上童鞋翻譯解釋:學習OpenCV——學習grabcut演算法   3、大致內容如下:

opencv2 學習第8天 提取分離前景背景

GrabCut 程式碼來自於http://www.cnblogs.com/tornadomeet/archive/2012/11/09/2763271.html #include <opencv2/highgui/highgui.hpp> #include &l

Matlab中米粒影象處理米粒個數大小計算

clear; clc; % 讀取圖片rice.png I=imread(‘rice.png’); % 獲取圖片的背景 BG=imopen(I,strel(‘disk’,15)); %得到背景均勻的圖片 I2=imsubtract(I,BG)

怎麼設定控制檯前景背景顏色

dos指令 :color [attr] 其中 attr        指定控制檯輸出的顏色屬性 顏色屬性由兩個十六進位制數字指定 -- 第一個為背景,第二個則為前景。 每個數字可以為以下任何值之一

影象分類物體檢測語義分割例項分割的聯絡區別

The task of labeling semantic objects in a scene requires that each pixel of an image be labeled as belonging to a category, such as sky, chair, floor, st

利用OpenCV的Grabcut()函式實現影象前景背景分割-並對Grabcut()作詳細介紹

Graphcut是一種基於圖論的分割方法,在計算機視覺領域中應用於前景分割、醫學處理、紋理分割及立體視覺等方面,類似於PS中的摳圖功能。基本圖論的分割技術是影象分割領域中新的研究熱點,該方法基於能量優化演算法,將影象分割問題轉換為圖的最小割優化問題。 Grabcut是Gra

區域生長區域分離與合併的影象分割方法

最近在學習影象分割的方法,所以對區域生長與區域分離與合併的影象分割方法進行一下總結。 首先說一下兩者的不同。區域生長是根據預先定義的生長準則來把畫素或子區域集合成較大區域的處理方法。區域生長是先給定影

(5).去重url爬取去重分離

日誌 %s .com 生成 can 實例對象 記錄日誌 lse 定制 # 新建py文件:duplication.py # 我們新建了一個文件,專門用來去重。在scrapy源碼中已經把結構寫好了,我們只需復制粘貼過來 from scrapy.dupefilter impor

南開大學提出最新邊緣檢測與影象分割演算法精度重新整理記錄(附開源地址)

  作者 | 劉雲、程明明、胡曉偉、邊佳旺等 譯者 | 劉暢 整理 | Jane 出品 | AI科技大本營 近日,南開大學媒體計算實驗室提出的最新邊緣檢測和影象過分割(可用於生成超畫素)被 IEEE PAMI 錄用。研究的第一作者也發微博稱:“這是第一個

dataset for semantic sgementation 影象分割任務中VOC的augment dataset 到底在哪?

      一、VOC12_AUG      大多數近期的論文都提到了,自己使用的是“we use augmented data with the annotation of XXX result in 10582 ,1449

0043-使用Grabcut函式完成前景背景分割

Graphcut主要用於影象背景與前景的分割,是一種基於圖論的分割方法,在計算機視覺領域中應用於前景分割、醫學處理、紋理分割及立體視覺等方面,類似於PS中的摳圖功能。基本圖論的分割技術是影象分割領域中新的研究熱點,該方法基於能量優化演算法,將影象分割問題轉換為圖的最小割優化問題。 Grabcut是G

Opencv中並行影象處理環境的搭建配置(opencv1.0 CUDA3.0vs2010)

這一章我們將介紹如何從頭搭建並配置一個用於影象處理的VC++平行計算環境。所用作業系統為Windows 7的32位系統,程式設計環境為VS2005,CUDA版本為3.0,OpenCV版本為1.0。內容包括建立一個基於VS2005的簡單的對話方塊工程,安裝和使用OpenCV,以及安裝配置CUDA環境。

watershed演算法影象分割

影象分割 學習opencv是為了工程應用,只學習不應用,等於白學習。下面分析一個影象分割的例子,以加強學習。 目標 學習使用cv::filter2D執行一些laplacian濾波來銳化影象 學習使用cv::distanceTransform來獲得二進位制影象的匯出表

ubuntu 下 ffmpeg 的安裝影象轉視訊壓縮視訊從視訊轉影象

1.Ubuntu下安裝 ffmpeg     可以通過如下的方式進行安裝[1] sudo add-apt-repository ppa:kirillshkrogalev/ffmpeg-next sudo apt-get update sudo apt-get install

卷積DFT,FFT,影象FFTFIR IIR 的物理意義

卷積:  衝擊訊號會對線性系統產生衝擊響應。  衝擊訊號可分解為平移度和幅度。其對線性系統的衝擊響應可以分解為點點間的經平移和縮放的各個衝擊響應的累加,通過卷積的表示式表示。  所謂的衝擊響應,就是線性系統對任何輸入訊號的響應,描述這種輸入輸出關係的算數方法就是卷積。

一起學opencv-python十(給影象加噪聲模糊處理影象銳化)

參考了https://www.bilibili.com/video/av24998616/?p=9 https://www.bilibili.com/video/av24998616/?p=10和 https://opencv-python-tutroals.readth

OpenCV 中影象處理類Mat類Ipllmage類

 Mat類是OpenCV 中最核心的類,全稱是Matrix,意為矩陣或者陣列的意思,該類的宣告在標頭檔案opencv2\core\core.hpp中,   Mat 類的建構函式如下:  Mat(int rows,int cols,int type)  其中rows代表矩

Opencv影象處理---基於距離變換分水嶺演算法的影象分割

程式碼 #include <opencv2/opencv.hpp> #include <iostream> using namespace std; using namespace cv; int main(int, char** argv) {

js陣列排序從小打到大從大到小陣列分離相同不同

    感覺有一段時間沒寫部落格,最近專案上面這兩個是比較實在並且實用的方法。其中效率個人不談,但是我都單獨抽離成了方法,需要的同學自取。 /*陣列排序演算法     * 第一個引數:排序的陣列