創建項目 | 文件與顯示 | 像素操作 | 圖像彩色類型轉換 | 模糊、平滑、去噪 | 銳化、邊緣檢測 | 二值化 | 形態學 | 位置變換 | 直方圖 | 霍夫變換 | 圖像優化 | 圖像分割
圖像分割是根據圖像中各部分的特徵,分割出不同的區域,這些區域可能代表了不同的物體。最簡單的圖像分割是區分出背景和前景。圖像分割目前有一些比較成熟的技術,但想不通過一些輔助手段而達到比較好的分割效果,還是有一定難度的。
一、漫水填充
如果用過Photoshop的讀者,應該對這項功能很熟悉。先設定一個閾值,然後在圖像中的某個區域點一下鼠標,類似這個區域的像素都會被填充爲某一顏色。這項功能需要我們指出ROI大概在哪裏,還要指出閾值使用多少。示例代碼如下:
Mat src = new Mat(img_desk);
Cv2.FloodFill(src, new OpenCvSharp.Point(233, 102), new Scalar(0, 0, 255), out OpenCvSharp.Rect rect, new Scalar(30, 30, 30), new Scalar(30, 30, 30));
src.SaveImage(img_result);
效果如下:
注:目標點在鍵盤的Space鍵裏。
二、分水嶺算法
分水嶺算法要求我們指出圖像中的哪些區域是連通的。給定一個跟圖像相同大小的矩陣,連通區域使用同一數字表示,例如上圖,筆記本區域標記爲1,鍵盤區域標記爲2等。這些區域只需要模糊標記(如果我們能準確標記,那就不需要這個算法做什麼事了)。
示例代碼如下:
Mat src = new Mat(img_desk);
Mat marker = new Mat(src.Rows, src.Cols, MatType.CV_32SC1);
for (int i = 0; i < 154; i++)
{
for (int j = 0; j < 91; j++)
{
marker.Set<int>(40 + j, 45 + i, 1);
}
}
for (int i = 0; i < 110; i++)
{
for (int j = 0; j < 234; j++)
{
marker.Set<int>(176 + j, 369 + i, 2);
}
}
for (int i = 0; i < 30; i++)
{
for (int j = 0; j < 30; j++)
{
marker.Set<int>(194 + j, 191 + i, 3);
}
}
Cv2.Watershed(src, marker);
Mat result = new Mat(marker.Rows, marker.Cols, MatType.CV_8UC3);
for (int i = 0; i < marker.Width; i++)
{
for (int j = 0; j < marker.Height; j++)
{
byte v = marker.Get<byte>(j, i);
switch (v)
{
case 1:
result.Set<Vec3b>(j, i, new Vec3b(255, 0, 0));
break;
case 2:
result.Set<Vec3b>(j, i, new Vec3b(0, 255, 0));
break;
case 3:
result.Set<Vec3b>(j, i, new Vec3b(0, 0, 255));
break;
}
}
}
result.SaveImage(img_result);
效果如下:
三、Grabcuts算法
Grabcuts算法利用標記區域的直方圖特徵,尋找相似的區域。標記區域需要爲矩形。
示例代碼如下:
Mat src = new Mat(img_desk);
Mat mask = new Mat();
Mat bgdModel = new Mat();
Mat fgdModel = new Mat();
Cv2.GrabCut(src, mask, new OpenCvSharp.Rect(90, 290, 180, 187), bgdModel, fgdModel, 12, GrabCutModes.InitWithRect);
Mat result = new Mat(mask.Rows, mask.Cols, MatType.CV_8UC1);
for (int i = 0; i < mask.Width; i++)
{
for (int j = 0; j < mask.Height; j++)
{
byte v = mask.Get<byte>(j, i);
switch (v)
{
case 0:
result.Set<byte>(j, i, 0);
break;
case 1:
result.Set<byte>(j, i, 255);
break;
case 2:
result.Set<byte>(j, i, 50);
break;
case 3:
result.Set<byte>(j, i, 200);
break;
}
}
}
result.SaveImage(img_result);
效果如下:
注:灰色區域是標記的,白色區域是找出來的線球。
四、Mean-Shift算法
Mean-Shift算法是本文唯一一個不需要事先標記區域的算法。它根據圖像顏色空間分佈的特徵進行分割。
示例代碼如下:
Mat src = new Mat(img_desk);
Mat result = new Mat();
Cv2.PyrMeanShiftFiltering(src, result, 5, 50);
result.SaveImage(img_result);
效果如下:
注:可以看到,筆記本和按鍵能夠被分割出來。