❶ 計算機圖形學中。寫出內點表示的8連通區域的遞歸填充演算法。 請寫出完整的函數代碼:
用八鄰域的話,有重復的,這個你要考慮到,一般都用四鄰域的,八鄰域你可以設置一個標志數組,對於已經處理的點就不管了
❷ opencv如何標記連通區域 並且提取連通區域
代碼
1)Two-pass演算法的一種實現
說明:
基於OpenCV和C++實現,領域:4-領域。實現與演算法描述稍有差別(具體為記錄具有相等關系的label方法實現上)。
// Connected Component Analysis/Labeling By Two-Pass Algorithm
// Author: www.icvpr.com
// Blog : http://blog.csdn.net/icvpr
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
void icvprCcaByTwoPass(const cv::Mat& _binImg, cv::Mat& _lableImg)
{
// connected component analysis (4-component)
// use two-pass algorithm
// 1. first pass: label each foreground pixel with a label
// 2. second pass: visit each labeled pixel and merge neighbor labels
//
// foreground pixel: _binImg(x,y) = 1
// background pixel: _binImg(x,y) = 0
if (_binImg.empty() ||
_binImg.type() != CV_8UC1)
{
return ;
}
// 1. first pass
_lableImg.release() ;
_binImg.convertTo(_lableImg, CV_32SC1) ;
int label = 1 ; // start by 2
std::vector<int> labelSet ;
labelSet.push_back(0) ; // background: 0
labelSet.push_back(1) ; // foreground: 1
int rows = _binImg.rows - 1 ;
int cols = _binImg.cols - 1 ;
for (int i = 1; i < rows; i++)
{
int* data_preRow = _lableImg.ptr<int>(i-1) ;
int* data_curRow = _lableImg.ptr<int>(i) ;
for (int j = 1; j < cols; j++)
{
if (data_curRow[j] == 1)
{
std::vector<int> neighborLabels ;
neighborLabels.reserve(2) ;
int leftPixel = data_curRow[j-1] ;
int upPixel = data_preRow[j] ;
if ( leftPixel > 1)
{
neighborLabels.push_back(leftPixel) ;
}
if (upPixel > 1)
{
neighborLabels.push_back(upPixel) ;
}
if (neighborLabels.empty())
{
labelSet.push_back(++label) ; // assign to a new label
data_curRow[j] = label ;
labelSet[label] = label ;
}
else
{
std::sort(neighborLabels.begin(), neighborLabels.end()) ;
int smallestLabel = neighborLabels[0] ;
data_curRow[j] = smallestLabel ;
// save equivalence
for (size_t k = 1; k < neighborLabels.size(); k++)
{
int tempLabel = neighborLabels[k] ;
int& oldSmallestLabel = labelSet[tempLabel] ;
if (oldSmallestLabel > smallestLabel)
{
labelSet[oldSmallestLabel] = smallestLabel ;
oldSmallestLabel = smallestLabel ;
}
else if (oldSmallestLabel < smallestLabel)
{
labelSet[smallestLabel] = oldSmallestLabel ;
}
}
}
}
}
}
// update equivalent labels
// assigned with the smallest label in each equivalent label set
for (size_t i = 2; i < labelSet.size(); i++)
{
int curLabel = labelSet[i] ;
int preLabel = labelSet[curLabel] ;
while (preLabel != curLabel)
{
curLabel = preLabel ;
preLabel = labelSet[preLabel] ;
}
labelSet[i] = curLabel ;
}
// 2. second pass
for (int i = 0; i < rows; i++)
{
int* data = _lableImg.ptr<int>(i) ;
for (int j = 0; j < cols; j++)
{
int& pixelLabel = data[j] ;
pixelLabel = labelSet[pixelLabel] ;
}
}
}
2)Seed-Filling種子填充方法
說明:
基於OpenCV和C++實現;領域:4-領域。
// Connected Component Analysis/Labeling By Seed-Filling Algorithm
// Author: www.icvpr.com
// Blog : http://blog.csdn.net/icvpr
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <stack>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
void icvprCcaBySeedFill(const cv::Mat& _binImg, cv::Mat& _lableImg)
{
// connected component analysis (4-component)
// use seed filling algorithm
// 1. begin with a foreground pixel and push its foreground neighbors into a stack;
// 2. pop the top pixel on the stack and label it with the same label until the stack is empty
//
// foreground pixel: _binImg(x,y) = 1
// background pixel: _binImg(x,y) = 0
if (_binImg.empty() ||
_binImg.type() != CV_8UC1)
{
return ;
}
_lableImg.release() ;
_binImg.convertTo(_lableImg, CV_32SC1) ;
int label = 1 ; // start by 2
int rows = _binImg.rows - 1 ;
int cols = _binImg.cols - 1 ;
for (int i = 1; i < rows-1; i++)
{
int* data= _lableImg.ptr<int>(i) ;
for (int j = 1; j < cols-1; j++)
{
if (data[j] == 1)
{
std::stack<std::pair<int,int>> neighborPixels ;
neighborPixels.push(std::pair<int,int>(i,j)) ; // pixel position: <i,j>
++label ; // begin with a new label
while (!neighborPixels.empty())
{
// get the top pixel on the stack and label it with the same label
std::pair<int,int> curPixel = neighborPixels.top() ;
int curX = curPixel.first ;
int curY = curPixel.second ;
_lableImg.at<int>(curX, curY) = label ;
// pop the top pixel
neighborPixels.pop() ;
// push the 4-neighbors (foreground pixels)
if (_lableImg.at<int>(curX, curY-1) == 1)
{// left pixel
neighborPixels.push(std::pair<int,int>(curX, curY-1)) ;
}
if (_lableImg.at<int>(curX, curY+1) == 1)
{// right pixel
neighborPixels.push(std::pair<int,int>(curX, curY+1)) ;
}
if (_lableImg.at<int>(curX-1, curY) == 1)
{// up pixel
neighborPixels.push(std::pair<int,int>(curX-1, curY)) ;
}
if (_lableImg.at<int>(curX+1, curY) == 1)
{// down pixel
neighborPixels.push(std::pair<int,int>(curX+1, curY)) ;
}
}
}
}
}
}
3)顏色標記(用於顯示)
// Connected Component Analysis/Labeling -- Color Labeling
// Author: www.icvpr.com
// Blog : http://blog.csdn.net/icvpr
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <stack>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
cv::Scalar icvprGetRandomColor()
{
uchar r = 255 * (rand()/(1.0 + RAND_MAX));
uchar g = 255 * (rand()/(1.0 + RAND_MAX));
uchar b = 255 * (rand()/(1.0 + RAND_MAX));
return cv::Scalar(b,g,r) ;
}
void icvprLabelColor(const cv::Mat& _labelImg, cv::Mat& _colorLabelImg)
{
if (_labelImg.empty() ||
_labelImg.type() != CV_32SC1)
{
return ;
}
std::map<int, cv::Scalar> colors ;
int rows = _labelImg.rows ;
int cols = _labelImg.cols ;
_colorLabelImg.release() ;
_colorLabelImg.create(rows, cols, CV_8UC3) ;
_colorLabelImg = cv::Scalar::all(0) ;
for (int i = 0; i < rows; i++)
{
const int* data_src = (int*)_labelImg.ptr<int>(i) ;
uchar* data_dst = _colorLabelImg.ptr<uchar>(i) ;
for (int j = 0; j < cols; j++)
{
int pixelValue = data_src[j] ;
if (pixelValue > 1)
{
if (colors.count(pixelValue) <= 0)
{
colors[pixelValue] = icvprGetRandomColor() ;
}
cv::Scalar color = colors[pixelValue] ;
*data_dst++ = color[0] ;
*data_dst++ = color[1] ;
*data_dst++ = color[2] ;
}
else
{
data_dst++ ;
data_dst++ ;
data_dst++ ;
}
}
}
}
4)測試程序
// Connected Component Analysis/Labeling -- Test code
// Author: www.icvpr.com
// Blog : http://blog.csdn.net/icvpr
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <stack>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
int main(int argc, char** argv)
{
cv::Mat binImage = cv::imread("../icvpr.com.jpg", 0) ;
cv::threshold(binImage, binImage, 50, 1, CV_THRESH_BINARY_INV) ;
// connected component labeling
cv::Mat labelImg ;
icvprCcaByTwoPass(binImage, labelImg) ;
//icvprCcaBySeedFill(binImage, labelImg) ;
// show result
cv::Mat grayImg ;
labelImg *= 10 ;
labelImg.convertTo(grayImg, CV_8UC1) ;
cv::imshow("labelImg", grayImg) ;
cv::Mat colorLabelImg ;
icvprLabelColor(labelImg, colorLabelImg) ;
cv::imshow("colorImg", colorLabelImg) ;
cv::waitKey(0) ;
return 0 ;
}
❸ 簡述邊界表示的四連通區域的種子填充演算法的基本思想和執行步驟
一、種子填充演算法思想:
首先填充種子所在的尚未填充的一區段,然後確定與這一區段相鄰的上下兩條掃描線上位於該區段內是否存在需要填充的新區段,如果存在,則依次把每個新區段最右端的象素作為種子放入堆棧。反復這個過程,直到堆棧為空。
二、種子填充演算法步驟:
1、初始化堆棧。
2、種子壓入堆棧。
3、While(堆棧非空)從堆棧彈出種子象素。
❹ matlab bwboundaries 函數思想原理
只不是一個簡單的問題
首先要明白這個函數是給出二值圖像的邊界
二值圖像就是數值只有0和1兩種值的圖像,或者叫邏輯真或假
其邊界,就是0和1數據的交接出,一般是求數據為1的區域的邊界
由於圖像中本身數據為一的區域可能不止一塊
所以最用邊界也可能不止一條,連在一起的一個全是1的區域,我們叫它做連通域
所以本身這個問題,可以分為兩個子問題
第一,求圖像的連通域
第二,求每個連通域的邊界
這兩個問題都不是簡單用一兩句語句就能解決的
對於第一個問題,matlab有bwlable函數標記每個連通域
而bwlable函數的具體工作代碼,matlab沒有給出
關鍵的函數的源代碼,matlab是保密的,所以不確切知道其所用的演算法
而具體的思想,是掃描矩陣,然後合拼互相連接的區域
你可以搜索 二值圖像 連通域 看看,有很多種演算法,效率各不相同,不知道matlab用的哪種
第二個問題,也不是個簡單的問題
在matlab內部bwboundaties函數首先是調用bwlable解決第一個問題的
而第二個問題又調用了一個內部的不提供源代碼的函數,所以具體演算法也不得而知
實際上連通域問題解決後,在單一連通域上提取邊界也不算太難
比較麻煩的是,在連通域中有洞的情況下,一個連通域也可能有多個邊界
一個對外的邊界,和若干個內部洞洞的邊界
如果是有心想學習演算法,最好多找資料看看。
如果只是想了解一下,嘗試自己編著玩玩,沒有很硬行的規定需要
還是用系統提供的現成函數好了,自己編的即便運行無誤多半效率不及系統提供的
❺ 對圖像中連通域進行標記並計算面積matlab
matlab里有連通域標記的函數bwlabel,具體自己help吧
至於求連通域面積,stats=regionprops(ibw,'Area');%ibw是標記號的圖
求中值也有這函數的,median(A)
別的就很隨意了
❻ 對於二值化圖像怎麼進行連通性分析並計算每一個連通性區域的大小
原型: int WINAPI icePub_imgToSingleBmp(char *strImgFilename,char *strBmpFilename,int thresholdValue) 輸入:strImgFilename 待處理圖像文件名 strBmpFilename bmp圖像名 thresholdValue 256級灰度值的閾值(函數會先將圖像轉換成灰度再根
❼ 求解格林公式復連通區域計算 其中根據圖11_13得兩式相減為0是如何得到的 求詳細過程
因為L+(-l)=0
什麼意思,我用L表示在外圈的積分,方向是逆時針,也就是正向.-l表示在內圈的積分,方向是順時針,也是正向.根據格林公式,L+(-l)=二重積分,但在這個多連通區域上,二重積分是0啊.為什麼是0自己去想.
所以就有L=l
❽ BWLABEL函數得到的是一個和原矩陣一樣size的矩陣,但裡面的連通域我怎麼算不清楚呢
看c++數據結構與演算法分析
❾ 誰能給個好用的連通域處理的演算法,要8鄰域的
樓主要處理的圖像是什麼樣的?黑白圖像還是彩色的?我這里有個以前用過的只針對黑白圖像的連通域處理,目標是白色,背景是黑色的,不過,如果你的圖像不是這樣的,那先二值化,然後變換為黑色背景白色目標的圖片 CodeGo.net,再調用我這個函數,先看懂我這個函數,然後修改為可以處理白色背景黑色目標 具體函數
其中THRESHOLD_JOINNUM 是個宏定義……
你要先把圖像的邊緣像素處理下,把邊緣1到2個像素寬度的位置,都置為背景色,否則,可能得不到正確的結果,也可能造成訪問越界。也就是把四周的邊緣像素都置為背景色 然後,如果你仔細看這個函數的實現的話,其實是使用兩次連通域處理,一次是用來把黑色的小區域變為白色,也就是填補目標區域中可能出現的小黑洞。然後第二次處理才是用來刪除那些小於閾值的白色目標小連通域 這個函數你要看明白才能正確使用。看吧。
2. 樓主要處理的圖像是什麼樣的?黑白圖像還是彩色的?我這里有個以前用過的只針對黑白圖像的連通域處理,目標是白色,背景是黑色的,不過,如果你的圖像不是這樣的,那先二值化,然後變換為黑色背景白色目標的圖片,再調用我這個函數,先看懂我這個函數,然後修改為可以處理白色背景黑色目標 具體函數