1. 程式人生 > >opencv用於醫學影象分割

opencv用於醫學影象分割

初衷

最近比較閒,跟同學聊天講到他的課題:醫學影象分割,提取左心室區域。

我就好奇要了原始圖片,發現超聲影象果然比紅外影象解析度低,他指給我左心室所在區域。

思路

拿到這張圖第一眼,腦海裡蹦出無數個小想法:

  • 感興趣區域為一個扇形,所以首先製作掩模;
  • 這種灰度分級模糊的影象,若想分類,可以試試Kmeans,或者直接用閾值分割;
  • 後續可以分析特徵,通過邊界跟蹤一類得到。

具體流程

  • 1、原圖通過k_means二分類,並得到二值分割圖;
  • 2、形態學處理將粘連區域拆分,去除連通區域內部空洞;
  • 3、掩模後只保留扇形內資料;
  • 4、提取輪廓並以面積為評估物件做篩選;
  • 5、歐式距離為評估物件,後續維護好目標跟蹤。(在後續分析視訊序列時,發現其實目標位置基本不會大的變化,只是在形狀發生變化,因此可以藉助歐式距離跟蹤)

製作扇形掩模

查詢opencv並沒有現成的繪製扇形函式,只有手動繪製了。
大概思路為:

  • 1、繪製扇形的圓弧;
  • 2、繪製兩條半徑,繪製半徑需要知道角點,所以牽扯些許三角函式的計算。

嘗試引數後,程式碼如下:

//生成扇形輪廓,角度
void get_fans(Mat &img,cv::Point center,double angle, int radius)
{

	ellipse(img, center, cv::Size(radius, radius), 0, 90 - angle / 2, 90 + angle / 2, Scalar(255, 255, 255), 3, 8);

	//計算扇形頂點座標,先計算弦長和高

	int chord_len = radius*sin(angle*3.14 / (2 * 180));

	int height = radius*cos(angle*3.14 / (2 * 180));

	//一左一右,中心點加偏移量即為頂點座標
	
	cv::Point corner_1 = center + cv::Point(-chord_len, height);

	cv::Point corner_2 = center + cv::Point(chord_len, height);

	line(img, center, corner_1, Scalar(255, 255, 255), 3, 8);

	line(img, center, corner_2, Scalar(255, 255, 255), 3, 8);

}

朋友只需要根據引數調整,就能得到他們專案所需要的掩模。這個程式只是生成一張扇形的輪廓,生成掩模,還需要提取輪廓重新繪製,並將內部填充。
這部分程式碼如下:

get_fans(maskImage, cv::Point(520, 0), 77.4, 806);

		vector<vector<cv::Point> > contours;//查詢輪廓	

		vector<cv::Vec4i> hierarchy;//輪廓需要

		findContours(maskImage, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

		maskImage = cv::Mat::zeros(cv::Size(srcImage.cols, srcImage.rows), CV_8UC1);

		//繪製自定義掩模,CV_FILLED表示完全填充內部
		drawContours(maskImage, contours, -1, cv::Scalar::all(255), CV_FILLED);

完整程式碼就不分享了,借用Kmeans在分類時存在需要不定時反色情形,在對視訊序列處理時,直接閾值化後效果也不錯。
Kmeans效果還是有那麼點的:

在這裡插入圖片描述

在這裡插入圖片描述