連通區域標記演算法
1. 如何將幾個連通區域分別用矩形框標注出來
圖像處理里有一種叫做Labeling處理的演算法。可以把二值圖劃分區域,標出不同的區域編號。只要計算每種編號的個數,就是對應區域的面積了。如果沒看懂,不是演算法難,是我表達的不好。哈。
2. 將一張圖二值化後,有很多連通區域,我想分別求出每一塊連通區域的面積,不知道有什麼好一點的演算法
圖像處理里有一種叫做Labeling處理的演算法。
可以把二值圖劃分區域,標出不同的區域編號。
只要計算每種編號的個數,就是對應區域的面積了。
如果沒看懂,不是演算法難,是我表達的不好。哈。
3. java代碼怎麼實現計算圖像二值連通區域的質心
一:幾何距(Geometric
Moments)知識與質心尋找原理
1.
Image
Moments是圖像處理中非常有用的演算法,可以用來計算區域圖像的質心,方向等幾何特性,同時Mpq的高階具有旋轉不變性,可以用來實現圖像比較分類,正是因為Moments有這些特性,很多手繪油畫效果也會基於該演算法來模擬實現。它的數學表達為:
它的低階M00,M01,
M10可以用來計算質心,中心化以後M11,M02,M20可以用來計算區域的方向/角度
2.
什麼是質心
就是通過該點,區域達到一種質量上的平衡狀態,可能物理學上講的比較多,簡單點的說就是規則幾何物體的中心,不規則的可以通過掛繩子的方法來尋找。
二:演算法流程
1.
輸入圖像轉換為二值圖像
2.
通過連通組件標記演算法找到所有的連通區域,並分別標記
3.
對每個連通區域運用計算幾何距演算法得到質心
4.
用不同顏色繪制連通區域與質心,輸出處理後圖像
三:演算法效果
左邊為原圖,
右邊藍色為連通組件標記演算法處理以後結果,白色點為質心
四:關鍵代碼解析
1.
計算幾何距演算法代碼
doublem00
=
moments(pixels,
width,
height,
0,
0);
doublexCr
=
moments(pixels,
width,
height,
1,
0)
/
m00;//
row
doubleyCr
=
moments(pixels,
width,
height,
0,
1)
/
m00;//
column
return
new
double[]{xCr,
yCr};
4. 誰能給個好用的連通域處理的演算法,要8鄰域的
樓主要處理的圖像是什麼樣的?黑白圖像還是彩色的?我這里有個以前用過的只針對黑白圖像的連通域處理,目標是白色,背景是黑色的,不過,如果你的圖像不是這樣的,那先二值化,然後變換為黑色背景白色目標的圖片 CodeGo.net,再調用我這個函數,先看懂我這個函數,然後修改為可以處理白色背景黑色目標 具體函數
其中THRESHOLD_JOINNUM 是個宏定義……
你要先把圖像的邊緣像素處理下,把邊緣1到2個像素寬度的位置,都置為背景色,否則,可能得不到正確的結果,也可能造成訪問越界。也就是把四周的邊緣像素都置為背景色 然後,如果你仔細看這個函數的實現的話,其實是使用兩次連通域處理,一次是用來把黑色的小區域變為白色,也就是填補目標區域中可能出現的小黑洞。然後第二次處理才是用來刪除那些小於閾值的白色目標小連通域 這個函數你要看明白才能正確使用。看吧。
2. 樓主要處理的圖像是什麼樣的?黑白圖像還是彩色的?我這里有個以前用過的只針對黑白圖像的連通域處理,目標是白色,背景是黑色的,不過,如果你的圖像不是這樣的,那先二值化,然後變換為黑色背景白色目標的圖片,再調用我這個函數,先看懂我這個函數,然後修改為可以處理白色背景黑色目標 具體函數
5. connected component是什麼意思
connected component
英[kəˈnektɪd kəmˈpəunənt]
美[kəˈnɛktɪd kəmˈponənt]
連通分支[量];
[例句]The crux of the algorithm comes in determining whether a node is the root of a strongly connected component.
演算法的關鍵是判斷一個結點是否是強連通分量的根。
6. 怎麼把連通區域標記的坐標求出來
你可以試試按照計算物體質心的方法計算:
就是求一個連通區域所有點的坐標平均值,比如第一行的就是X
=
(186+187)/2;
Y
=(5+5)/2;
7. 簡述邊界表示的四連通區域的種子填充演算法的基本思想和執行步驟
一、種子填充演算法思想:
首先填充種子所在的尚未填充的一區段,然後確定與這一區段相鄰的上下兩條掃描線上位於該區段內是否存在需要填充的新區段,如果存在,則依次把每個新區段最右端的象素作為種子放入堆棧。反復這個過程,直到堆棧為空。
二、種子填充演算法步驟:
1、初始化堆棧。
2、種子壓入堆棧。
3、While(堆棧非空)從堆棧彈出種子象素。
8. 如何判斷一個區域是否是連通的 matlab
matlab函數_連通區域
1、 matlab函數bwareaopen──刪除小面積對象
格式:BW2 = bwareaopen(BW,P,conn)
作用:刪除二值圖像BW中面積小於P的對象,默認情況下使用8鄰域。
演算法:
(1)Determine the connected components.
L = bwlabeln(BW, conn);
(2)Compute the area of each component.
S = regionprops(L, 'Area');
(3)Remove small objects.
bw2 = ismember(L, find([S.Area] >= P));
2、matlab函數bwarea──計算對象面積
格式:total = bwarea(BW)
作用:估計二值圖像中對象的面積。
註:該面積和二值圖像中對象的像素數目不一定相等。
3、matlab函數imclearborder──邊界對象抑制
格式:IM2 = imclearborder(IM,conn)
作用:抑制和圖像邊界相連的亮對象。若IM是二值圖,imclearborder將刪除和圖像邊界相連的對象。默認情況conn=8。
註:For grayscale images, imclearborder tends to rece the overall intensity level in addition to suppressing border structures.
演算法:
(1)Mask image is the input image.
(2)Marker image is zero everywhere except along the border, where it equals the mask image.
4、matlab函數bwboundaries──獲取對象輪廓
格式:B = bwboundaries(BW,conn)(基本格式)
作用:獲取二值圖中對象的輪廓,和OpenCV中cvFindContours函數功能類似。B是一個P×1的cell數組,P為對象個數,每個cell 是Q×2的矩陣,對應於對象輪廓像素的坐標。
5、matlab函數imregionalmin──獲取極小值區域
格式:BW = imregionalmin(I,conn)
作用:尋找圖像I的極小值區域(regional maxima),默認情況conn=8。
Regional minima are connected components of pixels with a constant intensity value, and whose external boundary pixels all have a higher value.
6、matlab函數bwulterode──距離變換的極大值
格式:BW2 = bwulterode(BW,method,conn)
作用:終極腐蝕。尋找二值圖像BW的距離變換圖的區域極大值(regional maxima)。用於距離變換的距離默認為euclidean,連通性為8鄰域。
7、regionprops統計被標記的區域的面積分布,顯示區域總數。
函數regionprops語法規則為:STATS = regionprops(L,properties)
該函數用來測量標注矩陣L中每一個標注區域的一系列屬性。
L中不同的正整數元素對應不同的區域,例如:L中等於整數1的元素對應區域1;L中等於整數2的元素對應區域2;以此類推。
返回值STATS是一個 長度為max(L(:))的結構數組,結構數組的相應域定義了每一個區域相應屬性下的度量。
Properties可以是由逗號分割的字元串列表、包含字元 串的單元數組、單個字元串'all'或者'basic'。如果properties等於字元串'all',則表4.1中的度量數據都將被計算;如果properties等於字元串'basic',則屬性:'Area','Centroid'和'BoundingBox'將被計算。表1就是所有有效的屬性字元串。
表1 屬性字元串列表----度量圖像區域的屬性或功能
'Area' 圖像各個區域中像素總個數
'BoundingBox' 包含相應區域的最小矩形
'Centroid' 每個區域的質心(重心)
'MajorAxisLength' 與區域具有相同標准二階中心矩的橢圓的長軸長度(像素意義下)
'MinorAxisLength' 與區域具有相同標准二階中心矩的橢圓的短軸長度(像素意義下)
'Eccentricity' 與區域具有相同標准二階中心矩的橢圓的離心率(可作為特徵)
'Orientation' 與區域具有相同標准二階中心矩的橢圓的長軸與x軸的交角(度)
'Image' 與某區域具有相同大小的邏輯矩陣
'FilledImage' 與某區域具有相同大小的填充邏輯矩陣
'FilledArea' 填充區域圖像中的on像素個數
'ConvexHull' 包含某區域的最小凸多邊形
'ConvexImage' 畫出上述區域最小凸多邊形
'ConvexArea' 填充區域凸多邊形圖像中的on像素個數
'EulerNumber' 幾何拓撲中的一個拓撲不變數——歐拉數
'Extrema' 八方向區域極值點
'EquivDiameter' 與區域具有相同面積的圓的直徑
'Solidity' 同時在區域和其最小凸多邊形中的像素比例
'Extent' 同時在區域和其最小邊界矩形中的像素比例
'PixelIdxList' 存儲區域像素的索引下標
'PixelList' 存儲上述索引對應的像素坐標
9. 怎麼標記二值圖連通區域matlab
1)imread把圖片讀進去2)設定黑白的標准大於0.5的認為是白色,小於0.5的認為是黑色;將讀進去的圖片轉化為只含01的矩陣。3)從上往下一行行的檢測,發現某一行存在1,就記錄這一行;然後繼續檢測,直到某一行中沒有1,再記錄沒有1的這一行。4)同理,從左往右一列列檢測,記錄出現1的列,和不再出現1的列。5)根據3)和4)就可以確定矩陣的邊界了,用比它大一圈像素標注一下就好了。ps:如何檢測一行存在1;比如矩陣A 的i行。if any(A(i,:)==1)
10. 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 ;
}