1. 程式人生 > >OpenCVForUnity二值化和灰度化

OpenCVForUnity二值化和灰度化

隨著csdn部落格系統升級,嘗試使用md寫文章,感覺還不錯。繼續使用OpenCVForUnity處理圖片,今次的效果是灰度化和二值化,當所有功能實現後,可能會做出一個unity版的美圖秀秀。

首先我們來確定一下兩者的概念。

  • 二值化,就是將影象上的畫素點的灰度值設定為0或255,也就是將整個影象呈現出明顯的只有黑和白的視覺效果。
  • 灰度化,在RGB模型中,如果R=G=B時,則彩色表示一種灰度顏色,其中R=G=B的值叫灰度值,因此,灰度影象每個畫素只需一個位元組存放灰度值(又稱強度值、亮度值),灰度範圍為0-255。

什麼,沒看懂?那看一下這張圖吧,解釋了什麼叫做“有一張好圖,就可以什麼也不用解釋了”。
lena

構建一個簡單的場景

很明顯,灰度圖的取值範圍比二值圖大,那麼我們就先生成灰度圖,再通過將灰度值設定為0或255生成二值圖。
這裡寫圖片描述

  • 建立一個空場景,使用ugui擺好一個RawImage(或Image),和兩個按鈕。
  • 建立一個Binaryzation類。Awake()中註冊RawImage的約束比例,和2個按鈕的點選方法,這裡我先把二值化按鈕互動關閉,灰度化處理後再啟用。
[SerializeField] private RawImage targetImage;
[SerializeField] private Button grayButton;
[SerializeField] private
Button binaryButton; private AspectRatioFitter aspectRatioFitter; void Awake() { aspectRatioFitter = targetImage.GetComponent<AspectRatioFitter>(); grayButton.onClick.AddListener(OnGray); binaryButton.interactable = false; binaryButton.onClick.AddListener(OnBinary); }
  • Start()中讀取一張本地圖片,並在RawImage上顯示這張圖片。注意這裡使用Imgcodecs.imread()這個API從本地讀取圖片,需要在讀取後做一些列通道轉換。
private Mat srcMat, dstMat;

void Start()
{
    srcMat = Imgcodecs.imread(Application.dataPath + "/Textures/kizuna.jpg", 1);

    List<Mat> channels = new List<Mat>();
    Core.split(srcMat, channels);
    Mat imageRed = new Mat();
    imageRed = channels[0];
    Mat imageGreen = new Mat();
    imageGreen = channels[1];
    Mat imageBlue = new Mat();
    imageBlue = channels[2];
    channels[0] = channels[2];
    channels[2] = imageRed;
    Mat mergeImage = new Mat();
    Core.merge(channels, srcMat);

    aspectRatioFitter.aspectRatio = (float)srcMat.width() / (float)srcMat.height();

    Texture2D t2d = new Texture2D(srcMat.width(), srcMat.height());
    Utils.matToTexture2D(srcMat, t2d);
    targetImage.texture = t2d;
}
  • 使用Imgproc.cvtColor()方法將之前讀取的Mat轉為灰度。程式碼裡也舉例了一種簡便的方法,在讀取時直接轉灰度,可省略轉換步驟。然後把Mat轉Texture2D,再顯示到RawImage上,完成影象灰度化的效果。
void OnGray()
{
    binaryButton.interactable = true;

    //方法1.讀取時就轉為灰度
    //srcMat = Imgcodecs.imread(Application.dataPath + "/Textures/kizuna.jpg", 0); //flag=0,將讀入的彩色影象直接以灰度影象讀入
    //方法2.將現有Mat轉為灰度
    Imgproc.cvtColor(srcMat, srcMat, Imgproc.COLOR_BGR2GRAY); // 轉為灰度影象

    Texture2D t2d = new Texture2D(srcMat.width(), srcMat.height());
    Utils.matToTexture2D(srcMat, t2d);
    targetImage.texture = t2d;
}
  • 將灰度的Mat克隆一個副本,使用Imgproc.threshold()進行二值化處理,通過閾值(minThresh, maxThresh)調節取值範圍。
private double minThresh = 200d; //0(黑)->255(白)
private double maxThresh = 250d;
void OnBinary()
{
    //克隆一個副本
    dstMat = srcMat.clone();
    //二值化處理
    Imgproc.threshold(srcMat, dstMat, minThresh, maxThresh, Imgproc.THRESH_BINARY_INV); //CV_THRESH_BINARY

    Texture2D t2d = new Texture2D(dstMat.width(), dstMat.height());
    Utils.matToTexture2D(dstMat, t2d);
    targetImage.texture = t2d;
}

最終效果

效果圖