select_shape算子是一个功能十分强大的算子,算子原型如下:
select_shape(Regions: SelectedRegions: Features, Operation, Min, Max:)
select_shape算子的功能是计算Regions中所有输入region的特征(Features),如果计算的特征在[Min,Max]区间内,则会将每一个符合要求的region(Operation = ‘and’)或者至少一个符合要求的region(Operation = 'or')复制到SelectedRegions中。
Regions:输入区域,比如connection算子的输出;
SelectedRegions:筛选后的输出区域;
Features:特征,常见的有:'area', 'row', 'column'等,详细内容请查询halcon算子region_features;
Operation: 'and' 或者 'or',and是输出所有符合要求的region,'or'是只输出一个符合要求的region即可
Min:特征的阈值下限,闭区间;
Max:特征的阈值上限,闭区间;
假如有如下halcon代码:
connection(src, region)
select_shape(region, selected_regions, 'area', 'and', min, max)
对应的OpenCV代码实现如下:
Mat labels, stats, centroids;
connectedComponentsWithStats(src, labels, stats, centroids);
// 相当于halcon中的select_shape算子
selectShapeAccordingArea(labels, stats, centroids, min, max);
其中selectShapeAccordingArea函数实现如下:
enum CONNECTIONS_STATS {
X = 0,
Y,
WIDTH,
HEIGHT,
AREA,
STATS_INDEX_MAX
};
void selectShapeAccordingArea(Mat& labels, Mat& stats, Mat& centroids, int min, int max)
{
// 更新stats, centroids
Mat tempStats, tempCentroids;
vector<int> index;
// 从1开始,不计算背景连通域
for (int i = 1; i < stats.rows; ++i) {
int area = stats.row(i).at<int>(0, AREA);
if (area >= min & area <= max) {
tempStats.push_back(stats.row(i));
tempCentroids.push_back(centroids.row(i));
index.push_back(i);
}
}
stats = tempStats;
centroids = tempCentroids;
// 更新labels
Mat mask(labels.size(), CV_8UC1, Scalar(0));
for (int i = 0; i < stats.rows; ++i) {
int rectX = stats.row(i).at<int>(0, X);
int rectY = stats.row(i).at<int>(0, Y);
int rectWidth = stats.row(i).at<int>(0, WIDTH);
int rectHeight = stats.row(i).at<int>(0, HEIGHT);
Rect roi(rectX, rectY, rectWidth, rectHeight);
mask(roi) = (labels(roi) == index[i]);
}
Mat tempLabels;
labels.copyTo(tempLabels, mask);
labels = tempLabels;
}
下面进行验证:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
int main()
{
Mat src(5,5,CV_8UC1, Scalar(0));
src.at<uchar>(0, 3) = 255;
src.at<uchar>(1, 3) = 255;
src.at<uchar>(0, 4) = 255;
src.at<uchar>(4, 4) = 255;
cout << "src: \n" << src << endl;
Mat labels, stats, centroids;
connectedComponentsWithStats(src, labels, stats, centroids);
cout << "before, labels: \n" << labels << endl;
cout << "before, stats: \n" << stats << endl;
cout << "before, centroids: \n" << centroids << endl;
selectShapeAccordingArea(labels, stats, centroids, 3, 4);
cout << "after, labels: \n" << labels << endl;
cout << "after, stats: \n" << stats << endl;
cout << "after, centroids: \n" << centroids << endl;
waitKey(0);
return 0;
}
输出结果如下:
从输出结果来看,面积为一的连通域已经被过滤,labels矩阵中只剩下一个连通域,stats和centroids矩阵都保留了对应连通域的特征。