有所更改,參數不求完備,但求實用。源碼參考D:\source\opencv-3.4.9\samples\cpp\connected_components.cpp
【二值圖認知糾正】
OpenCV中threshold()得到的二值圖其實是0、255(設定值)這兩個值的圖,而不是0、1的圖。
0、1圖是真正意義上的二值圖。在矩陣運算時(比如點乘),推薦用0、1的二值圖。OpenCV應該是隱蔽地把0、255歸一化到了0、1。
0、1圖有Halcon中Region的感覺(Halcon針對Region的處理,功能十分強大)。
【知識點】
二值圖中不同連通域顯示不同的顏色,主要是connectedComponents()函數的使用。
int connectedComponents(InputArray image, OutputArray labels,int connectivity = 8, int ltype = CV_32S);
image是threshold得到的二值圖,得到的labels是32位 short int(短整型)元素的矩陣(圖)。
假如image中有2個連通域,那么labels是只有0、1、2這三種數的矩陣(0標識背景,1、2標識2個連通域),返回值是3(三種數據)。

#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; Mat img; int threshval = 150; static void on_trackbar(int, void*) //滑動條回調函數 { Mat bw; threshold(img, bw, threshval, 255, THRESH_BINARY); //二值化,0、255 imshow("bw", bw);//bw是0、255的“二值圖” Mat labelImage; int nLabels = connectedComponents(bw, labelImage);//0、255的bw圖變成0、1、2……不同區域標識的labelImage(32位短整型) std::vector<Vec3b> colors(nLabels); //colors有nLabels個元素,每個元素有3維,即nLabels個彩色像素 colors[0] = Vec3b(0, 0, 0);//背景色,黑色 for (int label = 1; label < nLabels; ++label)//label從1開始,因為0所在區域是背景 { colors[label] = Vec3b((rand() & 255), (rand() & 255), (rand() & 255));//用於不同區域的隨機彩色 } Mat dst(img.size(), CV_8UC3); //與img等大的3通道的畫板dst for (int r = 0; r < dst.rows; ++r) { for (int c = 0; c < dst.cols; ++c) { int label = (int)labelImage.at<int>(r, c);//at<int>中int對應labelImage中元素類型(短整型) dst.at<Vec3b>(r, c) = colors[label]; //dst畫板上塗色,依據檢索的連通域標識圖labelImage中的值(0、1、2……)塗不同顏色 } } imshow("Connected Components", dst); } int main(int argc, const char** argv) { img = imread("lena.jpg", IMREAD_GRAYSCALE);//灰度讀取 imshow("Image", img); namedWindow("Connected Components", WINDOW_AUTOSIZE);//先窗體,后滑動條 createTrackbar("Threshold", "Connected Components", &threshval, 255, on_trackbar); on_trackbar(threshval, 0);//先執行一次,出圖。0無意義,裝飾品 waitKey(0); return 0; }
【參考】
