OpenCV實現圖像連通域
圖像的連通域是指圖像中具有相同像素值并且位置相鄰的像素組成的區(qū)域,連通域分析是指在圖像中尋找出彼此互相獨立的連通域并將其標記出來。
一般情況下,一個連通域內只包含一個像素值,因此為了防止像素值波動對提取不同連通域的影響,連通域分析常處理的是二值化后的圖像。
4-鄰域和8-鄰域:

常用的圖像鄰域分析法有兩遍掃描法和種子填充法。兩遍掃描法會遍歷兩次圖像,第一次遍歷圖像時會給每一個非0像素賦予一個數字標簽,當某個像素的上方和左側鄰域內的像素已經有數字標簽時,取兩者中的最小值作為當前像素的標簽,否則賦予當前像素一個新的數字標簽。第一次遍歷圖像的時候同一個連通域可能會被賦予一個或者多個不同的標簽。
種子填充法源于計算機圖像學,常用于對某些圖形進行填充。該方法首先將所有非0像素放到一個集合中,之后在集合中隨機選出一個像素作為種子像素,根據鄰域關系不斷擴充種子像素所在的連通域,并在集合中刪除掉擴充出的像素,直到種子像素所在的連通域無法擴充,之后再從集合中隨機選取一個像素作為新的種子像素,重復上述過程直到集合中沒有像素。
CV_EXPORTS_AS(connectedComponentsWithAlgorithm) int connectedComponents(InputArray image, OutputArray labels,
int connectivity, int ltype, int ccltype);
- image:待標記不同連通域的單通道圖像,數據類型必須為CV_8U。
- labels:標記不同連通域后的輸出圖像,與輸入圖像具有相同的尺寸。
- connectivity:標記連通域時使用的鄰域種類,4表示4-鄰域,8表示8-鄰域。
- ltype:輸出圖像的數據類型,目前支持CV_32S和CV_16U兩種數據類型。
- ccltype:標記連通域時使用的算法類型標志,可以選擇的參數及含義在表中給出

該函數用于計算二值圖像中連通域的個數,并在圖像中將不同的連通域用不同的數字標簽標記出,其中標簽0表示圖像中的背景區(qū)域,同時函數具有一個int類型的返回數據,用于表示圖像中連通域的數目。函數的第一個參數是待標記連通域的輸入圖像,函數要求輸入圖像必須是數據類型為CV_8U的單通道灰度圖像,而且最好是經過二值化的二值圖像。函數第二個參數是標記連通域后的輸出圖像,圖像尺寸與第一個參數的輸入圖像尺寸相同,圖像的數據類型與函數的第四個參數相關。函數第三個參數是統(tǒng)計連通域時選擇的鄰域種類,函數支持兩種鄰域,分別用4表示4-鄰域,8表示8-鄰域。函數第四個參數為輸出圖像的數據類型,可以選擇的參數為CV_32S和CV_16U兩種。函數的最后一個參數是標記連通域時使用算法的標志,可以選擇的參數及含義在表給出,目前只支持Grana(BBDT)和Wu(SAUF)兩種算法。
OpenCV 還給出了簡單的函數形式
int connectedComponents(InputArray image, OutputArray labels,
int connectivity = 8, int ltype = CV_32S);
- image:待標記不同連通域的圖像單通道,數據類型必須為CV_8U。
- labels:標記不同連通域后的輸出圖像,與輸入圖像具有相同的尺寸。
- connectivity:標記連通域時使用的鄰域種類,4表示4-鄰域,8表示8-鄰域,默認參數為8。
- ltype:輸出圖像的數據類型,目前支持CV_32S和CV_16U兩種數據類型,默認參數為CV_32S。
該函數原型只有四個參數,前兩個參數分別表示輸入圖像和輸出圖像,第三個參數表示統(tǒng)計連通域時選擇的鄰域種類,分別用4表示4-鄰域,8表示8-鄰域,參數的默認值為8。最后一個參數表示輸出圖像的數據類型,可以選擇的參數為CV_32S和CV_16U兩種,參數的默認值為CV_32S。該函數原型有兩個參數具有默認值,在使用時最少只需要兩個參數,極大的方便了函數的調用。
進一步統(tǒng)計每個連通域的中心位置、矩形區(qū)域大小、區(qū)域面積等信息
復雜的
CV_EXPORTS_AS(connectedComponentsWithStatsWithAlgorithm) int connectedComponentsWithStats(InputArray image, OutputArray labels,
OutputArray stats, OutputArray centroids,
int connectivity, int ltype, int ccltype);
- image:待標記不同連通域的單通道圖像,數據類型必須為CV_8U。
- labels:標記不同連通域后的輸出圖像,與輸入圖像具有相同的尺寸。
- stats:含有不同連通域統(tǒng)計信息的矩陣,矩陣的數據類型為CV_32S。矩陣中第i行是標簽為i的連通域的統(tǒng)計特性,存儲的統(tǒng)計信息種類在表6-4中給出。
- centroids:每個連通域的質心坐標,數據類型為CV_64F。
- connectivity:標記連通域時使用的鄰域種類,4表示4-鄰域,8表示8-鄰域。
- ltype:輸出圖像的數據類型,目前支持CV_32S和CV_16U兩種數據類型。
- ccltype:標記連通域使用的算法類型標志,可以選擇的參數及含義在表中給出。
該函數能夠在圖像中不同連通域標記標簽的同時統(tǒng)計每個連通域的中心位置、矩形區(qū)域大小、區(qū)域面積等信息。函數的前兩個參數含義與connectedComponents()函數的前兩個參數含義一致,都是輸入圖像和輸出圖像。函數的第三個參數為每個連通域統(tǒng)計信息矩陣,如果圖像中有N個連通域,那么該參數輸出的矩陣尺寸為N×5,矩陣中每一行分別保存每個連通域的統(tǒng)計特性,詳細的統(tǒng)計特性在表中給出,如果想讀取包含第i個連通域的邊界框的水平長度,可以通過stats.at(i, CC_STAT_WIDTH)或者stats.at(i, 0)進行讀取。函數的第四個參數為每個連通域質心的坐標,如果圖像中有N個連通域,那么該參數輸出的矩陣尺寸為N×2,矩陣中每一行分別保存每個連通域質心的x坐標和y坐標,可以通過centroids.at(i, 0)和 centroids.at(i, 1) 分別讀取第i個連通域質心的x坐標和y坐標。函數第五個參數是統(tǒng)計連通域時選擇的鄰域種類,函數支持兩種鄰域,分別用4表示4-鄰域,8表示8-鄰域。函數第六個參數為輸出圖像的數據類型,可以選擇的參數為CV_32S和CV_16U兩種。函數的最后一個參數是標記連通域使用的算法,可以選擇的參數在上表給出,目前只支持Grana(BBDT)和Wu(SAUF)兩種算法。

簡單的
int connectedComponentsWithStats(InputArray image, OutputArray labels,
OutputArray stats, OutputArray centroids,
int connectivity = 8, int ltype = CV_32S);
- image:待標記不同連通域的單通道圖像,數據類型必須為CV_8U。
- labels:標記不同連通域后的輸出圖像,與輸入圖像具有相同的尺寸。
- stats:不同連通域的統(tǒng)計信息矩陣,矩陣的數據類型為CV_32S。矩陣中第i行是標簽為i的連通域的統(tǒng)計特性,存儲的統(tǒng)計信息種類在表6-4中給出。
- centroids:每個連通域的質心坐標,數據類型為CV_64F。
- connectivity:標記連通域時使用的鄰域種類,4表示4-鄰域,8表示8-鄰域,默認參數值為8。
- ltype:輸出圖像的數據類型,目前只支持CV_32S和CV_16U這兩種數據類型,默認參數值為CV_32S。
該函數原型只有六個參數,前兩個參數分別表示輸入圖像和輸出圖像,第三個參數表示每個連通域的統(tǒng)計信息,第四個參數表示每個連通域的質心位置。后兩個參數分別表示統(tǒng)計連通域時選擇的鄰域種類,分別用4表示4-鄰域,8表示8-鄰域,參數的默認值為8。最后一個參數表示輸出圖像的數據類型,可以選擇的參數為CV_32S和CV_16U兩種,參數的默認值為CV_32S。該函數原型有兩個參數具有默認值,在使用時最少只需要四個參數,極大的方便了函數的調用。
簡單示例
//
// Created by smallflyfly on 2021/6/16.
//
#include "opencv2/opencv.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main() {
Mat im = imread("rice.jfif");
Mat gray;
cvtColor(im, gray, CV_BGR2GRAY);
// resize(im, im, Size(0, 0), 0.5, 0.5);
imshow("im", im);
Mat im1;
threshold(gray, im1, 125, 255, THRESH_BINARY);
imshow("im1", im1);
// waitKey(0);
RNG rng(10010);
Mat out;
int num = connectedComponents(im1, out, 8, CV_16U);
vector<Vec3b> colors;
for (int i=0; i<num; i++) {
// 使用均勻分布的隨機確定顏色
Vec3b vec = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
colors.push_back(vec);
}
Mat result = Mat::zeros(im.size(), im.type());
for (int i = 0; i < im.rows; ++i) {
for (int j = 0; j < im.cols; ++j) {
int label = out.at<uint16_t>(i, j);
if (label == 0) {
continue;
}
result.at<Vec3b>(i, j) = colors[label];
}
}
imshow("result", result);
Mat labels, stats, centroids;
int count = connectedComponentsWithStats(im1, labels, stats, centroids, 8);
cout << count << endl;
for (int i = 1; i < count; ++i) {
int x = centroids.at<double>(i, 0);
int y = centroids.at<double>(i, 1);
cout << x << " " << y << endl;
circle(im, Point(x, y), 2, Scalar(0, 0, 255), -1);
int xmin = stats.at<int>(i, CC_STAT_LEFT);
int ymin = stats.at<int>(i, CC_STAT_TOP);
int w = stats.at<int>(i, CC_STAT_WIDTH);
int h = stats.at<int>(i, CC_STAT_HEIGHT);
Rect rect(xmin, ymin, w, h);
rectangle(im, rect, Scalar(0, 255, 255), 2);
putText(im, to_string(i), Point(x+5, y), FONT_HERSHEY_SCRIPT_SIMPLEX, 1, Scalar(0, 0, 255), 2);
}
imshow("im", im);
waitKey(0);
destroyAllWindows();
return 0;
}
簡單雙色圖效果比較明顯 百度圖片搜的

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
解析C++中的for循環(huán)以及基于范圍的for語句使用
這篇文章主要介紹了解析C++中的for循環(huán)以及基于范圍的for語句使用,是C++入門學習中的基礎知識,需要的朋友可以參考下2016-01-01

