欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Opencv求取連通區(qū)域重心實例

 更新時間:2020年06月04日 16:49:56   作者:蘇丶  
這篇文章主要介紹了Opencv求取連通區(qū)域重心實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

我們有時候需要求取某一個物體重心,這里一般將圖像二值化,得出該物體的輪廓,然后根據(jù)灰度重心法,計算出每一個物體的中心。

步驟如下:

1)合適的閾值二值化

2)求取輪廓

3)計算重心

otsu算法求取最佳閾值

otsu法(最大類間方差法,有時也稱之為大津算法)使用的是聚類的思想,把圖像的灰度數(shù)按灰度級分成2個部分,使得兩個部分之間的灰度值差異最大,每個部分之間的灰度差異最小,通過方差的計算來尋找一個合適的灰度級別來劃分,otsu算法被認(rèn)為是圖像分割中閾值選取的最佳算法,計算簡單,不受圖像亮度和對比度的影響。因此,使類間方差最大的分割意味著錯分概率最小。

計算輪廓

opencv中函數(shù)findContours函數(shù)

findContours(二值化圖像,輪廓,hierarchy,輪廓檢索模式,輪廓近似辦法,offset)

灰度重心法

利用灰度重心法計算中心,灰度重心法將區(qū)域內(nèi)每一像素位置處的灰度值當(dāng)做該點的“質(zhì)量”,其求區(qū)域中心的公式為:

其中,f(u,v)是坐標(biāo)為(u,v)的像素點的灰度值, 是目標(biāo)區(qū)域集合, 是區(qū)域中心坐標(biāo),灰度重心法提取的是區(qū)域的能量中心。

//otsu算法實現(xiàn)函數(shù)
int Otsu(Mat &image)
{
  int width = image.cols;
  int height = image.rows;
  int x = 0, y = 0;
  int pixelCount[256];
  float pixelPro[256];
  int i, j, pixelSum = width * height, threshold = 0;

  uchar* data = (uchar*)image.data;

  //初始化 
  for (i = 0; i < 256; i++)
  {
    pixelCount[i] = 0;
    pixelPro[i] = 0;
  }

  //統(tǒng)計灰度級中每個像素在整幅圖像中的個數(shù) 
  for (i = y; i < height; i++)
  {
    for (j = x; j<width; j++)
    {
      pixelCount[data[i * image.step + j]]++;
    }
  }


  //計算每個像素在整幅圖像中的比例 
  for (i = 0; i < 256; i++)
  {
    pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
  }

  //經(jīng)典ostu算法,得到前景和背景的分割 
  //遍歷灰度級[0,255],計算出方差最大的灰度值,為最佳閾值 
  float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;
  for (i = 0; i < 256; i++)
  {
    w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;

    for (j = 0; j < 256; j++)
    {
      if (j <= i) //背景部分 
      {
        //以i為閾值分類,第一類總的概率 
        w0 += pixelPro[j];
        u0tmp += j * pixelPro[j];
      }
      else    //前景部分 
      {
        //以i為閾值分類,第二類總的概率 
        w1 += pixelPro[j];
        u1tmp += j * pixelPro[j];
      }
    }

    u0 = u0tmp / w0;    //第一類的平均灰度 
    u1 = u1tmp / w1;    //第二類的平均灰度 
    u = u0tmp + u1tmp;   //整幅圖像的平均灰度 
                //計算類間方差 
    deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
    //找出最大類間方差以及對應(yīng)的閾值 
    if (deltaTmp > deltaMax)
    {
      deltaMax = deltaTmp;
      threshold = i;
    }
  }
  //返回最佳閾值; 
  return threshold;
}

int main()
{
  Mat White=imread("white.tif");//讀取圖像
  int threshold_white = otsu(White);//閾值計算,利用otsu
  cout << "最佳閾值:" << threshold_white << endl;
  Mat thresholded = Mat::zeros(White.size(), White.type());
  threshold(White, thresholded, threshold_white, 255, CV_THRESH_BINARY);//二值化
  vector<vector<Point>>contours;
  vector<Vec4i>hierarchy;
  findContours(thresholded, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);//查找輪廓

  int i = 0;
  int count = 0;
  Point pt[10];//假設(shè)有三個連通區(qū)域
  Moments moment;//矩
  vector<Point>Center;//創(chuàng)建一個向量保存重心坐標(biāo)
  for (; i >= 0; i = hierarchy[i][0])//讀取每一個輪廓求取重心
  {
    Mat temp(contours.at(i));
    Scalar color(0, 0, 255);
    moment = moments(temp, false);
    if (moment.m00 != 0)//除數(shù)不能為0
    {
      pt[i].x = cvRound(moment.m10 / moment.m00);//計算重心橫坐標(biāo)
      pt[i].y = cvRound(moment.m01 / moment.m00);//計算重心縱坐標(biāo)

    }
      Point p = Point(pt[i].x, pt[i].y);//重心坐標(biāo)
      circle(White, p, 1, color, 1, 8);//原圖畫出重心坐標(biāo)
      count++;//重心點數(shù)或者是連通區(qū)域數(shù)
      Center.push_back(p);//將重心坐標(biāo)保存到Center向量中
    }
  }
  cout << "重心點個數(shù):" << Center.size() << endl;
  cout << "輪廓數(shù)量:" << contours.size() << endl;
  imwrite("Center.tif", White);
}

原圖:

二值化:

重心點:

補充知識:opencv 根據(jù)模板凸包求閾值化后的輪廓組合

圖像處理中,要求特征與背景的對比度高,同時,合適的圖像分割也是解決問題的關(guān)鍵。

博主以前的方法,默認(rèn)為特征必然是最大的連通域,所以閾值化后,查找輪廓,直接提取面積最大的輪廓即可。

但可能會存在另一種情況,不論怎么閾值化和膨脹,想要的特征被分成好幾塊,也即斷開了。此時,再加上一些不可預(yù)測的干擾和噪聲,findcontours之后,會得到很多輪廓。

那么問題來了,我們需要的是哪個輪廓,或者是哪幾個輪廓組合的區(qū)域?

本文的意義也在于此。

根據(jù)模板的凸包,求出圖像中最相似的輪廓組合。

本方法,主要用到matchshapes函數(shù),并基于這樣一個前提:模板凸包的2/3部分,與模板凸包的相似度,大于模板凸包的1/2部分。

話不多說,上代碼。

void getAlikeContours(std::vector<cv::Point> Inputlist, cv::Mat InputImage, std::vector<cv::Point> &Outputlist)
{
 Mat image;
 InputImage.copyTo(image);
 vector<vector<Point> > contours;
 findContours(image, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);//查找最外層輪廓
 for (int idx = contours.size() - 1; idx >= 0; idx--)
  {
	for (int i = contours[idx].size() - 1; i >= 0; i--)
	{
		if (contours[idx][i].x == 1 || contours[idx][i].y == 1 || contours[idx][i].x == image.cols - 2 || contours[idx][i].y == image.rows - 2)
		{
			swap(contours[idx][i], contours[idx][contours[idx].size() - 1]);
			contours[idx].pop_back();
			
		}
	}
	//可能會存在空的輪廓,把他們刪除
	for (int idx = contours.size() - 1; idx >= 0; idx--)
	{
		if (contours[idx].size() == 0) contours.erase(contours.begin() + idx);
	}
 
	while (true)
	{
		if (contours.size() == 0) break;
		if (contours.size() == 1)
		{
			vector<Point> finalList;
			finalList.assign(contours[0].begin(), contours[0].end());
			convexHull(Mat(finalList), Outputlist, true);
			break;
		}
 
		int maxContourIdx = 0;
		int maxContourPtNum = 0;
		for (int index = contours.size() - 1; index >= 0; index--)
		{
			if (contours[index].size() > maxContourPtNum)
			{
				maxContourPtNum = contours[index].size();
				maxContourIdx = index;
			}
		}
		//第二大輪廓
		int secondContourIdx = 0;
		int secondContourPtNum = 0;
		for (int index = contours.size() - 1; index >= 0; index--)
		{
			if (index == maxContourIdx) continue;
			if (contours[index].size() > secondContourPtNum)
			{
				secondContourPtNum = contours[index].size();
				secondContourIdx = index;
			}
		}
		vector<Point> maxlist;
		vector<Point> maxAndseclist;
		vector<Point> maxlistHull;
		vector<Point> maxAndseclistHull;
		maxlist.insert(maxlist.end(), contours[maxContourIdx].begin(), contours[maxContourIdx].end());
		maxAndseclist.insert(maxAndseclist.end(), contours[maxContourIdx].begin(), contours[maxContourIdx].end());
		maxAndseclist.insert(maxAndseclist.end(), contours[secondContourIdx].begin(), contours[secondContourIdx].end());
		convexHull(Mat(maxlist), maxlistHull, true);
		convexHull(Mat(maxAndseclist), maxAndseclistHull, true);
		double maxcontourScore = matchShapes(Inputlist, maxlistHull, CV_CONTOURS_MATCH_I1, 0);
		double maxandseccontourScore = matchShapes(Inputlist, maxAndseclistHull, CV_CONTOURS_MATCH_I1, 0);
		if (maxcontourScore>maxandseccontourScore)
		{
			contours[maxContourIdx].insert(contours[maxContourIdx].end(), contours[secondContourIdx].begin(), contours[secondContourIdx].end());
		}
		contours.erase(contours.begin() + secondContourIdx);
	}
}

以上這篇Opencv求取連通區(qū)域重心實例就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • python Tornado框架的使用示例

    python Tornado框架的使用示例

    這篇文章主要介紹了python Tornado框架的使用示例,幫助大家更好的利用python進(jìn)行web開發(fā),感興趣的朋友可以了解下
    2020-10-10
  • python實現(xiàn)修改xml文件內(nèi)容

    python實現(xiàn)修改xml文件內(nèi)容

    這篇文章主要介紹了python實現(xiàn)修改xml文件內(nèi)容,XML 指可擴展標(biāo)記語言,是一種標(biāo)記語言,是從標(biāo)準(zhǔn)通用標(biāo)記語言(SGML)中簡化修改出來的
    2022-07-07
  • pytorch 獲取層權(quán)重,對特定層注入hook, 提取中間層輸出的方法

    pytorch 獲取層權(quán)重,對特定層注入hook, 提取中間層輸出的方法

    今天小編就為大家分享一篇pytorch 獲取層權(quán)重,對特定層注入hook, 提取中間層輸出的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • 使用Python實現(xiàn)二分法查找的示例

    使用Python實現(xiàn)二分法查找的示例

    這篇文章主要介紹了使用Python實現(xiàn)二分法查找的示例,二分法通常又叫二分查找,一般用于查找一個有序數(shù)組中的某個值的位置或者給定的特定值的插入位置,需要的朋友可以參考下
    2023-04-04
  • python+pygame實現(xiàn)坦克大戰(zhàn)小游戲的示例代碼(可以自定義子彈速度)

    python+pygame實現(xiàn)坦克大戰(zhàn)小游戲的示例代碼(可以自定義子彈速度)

    這篇文章主要介紹了python+pygame實現(xiàn)坦克大戰(zhàn)小游戲---可以自定義子彈速度,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • python服務(wù)器中發(fā)送外部請求的基本步驟

    python服務(wù)器中發(fā)送外部請求的基本步驟

    在Python中,服務(wù)器發(fā)送外部請求是一個常見的操作,尤其是在需要集成不同服務(wù)或API時,有多種庫可以幫助你完成這項任務(wù),但最流行和廣泛使用的庫之一是requests,下面給大家分享python服務(wù)器中發(fā)送外部請求的基本步驟,感興趣的朋友一起看看吧
    2024-08-08
  • 詳解Python如何輕松實現(xiàn)定時執(zhí)行任務(wù)

    詳解Python如何輕松實現(xiàn)定時執(zhí)行任務(wù)

    這篇文章主要為大家詳細(xì)介紹了Python如何在Windows下不用任務(wù)管理器就實現(xiàn)輕松定時執(zhí)行任務(wù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下
    2022-10-10
  • python 進(jìn)制轉(zhuǎn)換 int、bin、oct、hex的原理

    python 進(jìn)制轉(zhuǎn)換 int、bin、oct、hex的原理

    這篇文章主要介紹了python 進(jìn)制轉(zhuǎn)換 int、bin、oct、hex的原理,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • 詳解Python 最短匹配模式

    詳解Python 最短匹配模式

    這篇文章主要介紹了如何實現(xiàn)Python 最短匹配模式,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • Python中.py程序在CMD控制臺以指定虛擬環(huán)境運行

    Python中.py程序在CMD控制臺以指定虛擬環(huán)境運行

    本文主要介紹了Python中.py程序在CMD控制臺以指定虛擬環(huán)境運行,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07

最新評論