OpenCVForUnity二值化和灰度化
阿新 • • 發佈:2019-02-12
隨著csdn部落格系統升級,嘗試使用md寫文章,感覺還不錯。繼續使用OpenCVForUnity處理圖片,今次的效果是灰度化和二值化,當所有功能實現後,可能會做出一個unity版的美圖秀秀。
首先我們來確定一下兩者的概念。
- 二值化,就是將影象上的畫素點的灰度值設定為0或255,也就是將整個影象呈現出明顯的只有黑和白的視覺效果。
- 灰度化,在RGB模型中,如果R=G=B時,則彩色表示一種灰度顏色,其中R=G=B的值叫灰度值,因此,灰度影象每個畫素只需一個位元組存放灰度值(又稱強度值、亮度值),灰度範圍為0-255。
什麼,沒看懂?那看一下這張圖吧,解釋了什麼叫做“有一張好圖,就可以什麼也不用解釋了”。
構建一個簡單的場景
很明顯,灰度圖的取值範圍比二值圖大,那麼我們就先生成灰度圖,再通過將灰度值設定為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;
}