本系列代码托管于:https://github.com/chintsan-code/opencv4-tutorials
本篇使用的项目为:ccl
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, const char** argv) {
Mat src = imread("../sample/rice.png");
if (src.empty()) {
cout << "could not load image..." << endl;
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
GaussianBlur(src, src, Size(3, 3), 0);
Mat gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
imshow("binary", binary);
Mat labels = Mat::zeros(binary.size(), CV_32S);
Mat stats, centroids;
int num_labels = connectedComponentsWithStats(binary, labels, stats, centroids, 8, CV_32S, CCL_DEFAULT);
vector<Vec3b> colorTable(num_labels);
// backgound color
colorTable[0] = Vec3b(0, 0, 0);
RNG rng(12345);
for (int i = 1; i < num_labels; i++) {
colorTable[i] = Vec3b(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
}
Mat result = Mat::zeros(binary.size(), CV_8UC3);
int w = result.cols;
int h = result.rows;
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
int label = labels.at<int>(row, col);
result.at<Vec3b>(row, col) = colorTable[label];
}
}
for (int i = 1; i < num_labels; i++) {
// center
int cx = centroids.at<double>(i, 0); // 参数0代表获取中心x坐标
int cy = centroids.at<double>(i, 1); // 参数1代表获取中心y坐标
// rectangle and area
int x = stats.at<int>(i, CC_STAT_LEFT);
int y = stats.at<int>(i, CC_STAT_TOP);
int width = stats.at<int>(i, CC_STAT_WIDTH);
int height = stats.at<int>(i, CC_STAT_HEIGHT);
int area = stats.at<int>(i, CC_STAT_AREA);
// 绘制
drawMarker(result, Point(cx, cy), Scalar(0, 0, 255), MARKER_TILTED_CROSS,10);
//circle(result, Point(cx, cy), 3, Scalar(0, 0, 255), 2, 8, 0);
// 外接矩形
Rect box(x, y, width, height);
rectangle(result, box, Scalar(0, 255, 0), 2, 8);
putText(result, format("%d", area), Point(x, y), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 255, 0), 1);
}
putText(result, format("number: %d", num_labels - 1), Point(10, 10), FONT_HERSHEY_PLAIN, 1.0, Scalar(0, 255, 0), 1);
printf("total labels : %d \n", (num_labels - 1));
imshow("CCL demo", result);
waitKey(0);
destroyAllWindows();
return 0;
}
四邻域与八邻域
常见算法
(1)基于像素扫描的方法:重复计算较多
(2)基于块扫描方法:减少了重复计算
(3)两步法扫描
connectedComponents:不携带附加信息的联通组件扫描
int connectedComponents(InputArray image, OutputArray labels, int connectivity, int ltype, int ccltype);
- image:输入图像,8-bit单通道图像
- labels:目标图像,每个像素都有一个label。背景的label为0
- connectivity:8或4,代表8-邻域或4-邻域
- ltype:输出的labels类型。CV_32S或CV_16U
- ccltype:算法类型
- CCL_DEFAULT:8-邻域BBTD
- CCL_WU
- CCL_GRANA
- @return:label数量。这里包括了背景,所以应该减去1
connectedComponentsWithStats:携带附加信息的联通组件扫描
int connectedComponentsWithStats(InputArray image, OutputArray labels, OutputArray stats, OutputArray centroids, int connectivity, int ltype, int ccltype);
- image: 输入图像,8-bit单通道图像
- labels: 目标图像,每个像素都有一个label。背景的label为0
- stats:每个label的统计信息
- CC_STAT_LEFT:外界矩形左上角x坐标
- CC_STAT_TOP:外界矩形左上角y坐标
- CC_STAT_WIDTH:外界矩形宽
- CC_STAT_HEIGHT:外界矩形高
- CC_STAT_AREA:像素面积
- centroids:每个label的中心坐标
- centroids.at(label, 0); // 获取中心x坐标
- centroids.at(label, 1); // 获取中心y坐标
- connectivity:8或4,代表8-邻域或4-邻域
- ltype:输出的labels类型。CV_32S或CV_16U
- ccltype:算法类型
- CCL_DEFAULT:8-邻域BBTD
- CCL_WU
- CCL_GRANA
- @return:label数量。这里包括了背景,所以应该减去1
评论 (0)