C++实现imregionalmax函数
- [1 说明](#1 说明)
- [2 示例](#2 示例)
- [3 C++实现](#3 C++实现)
1 说明
Matlab imregionalmax
bash
BW = imregionalmax(I)
返回标识灰度图像 I 中区域最大值的二值图像BW。
区域最大值点是具有同一强度值的连通像素分量,其周围的像素强度值比该值低。
BW --- 逻辑数组
区域最大值的位置,以与 I 大小相同的逻辑数组形式返回。值为 1 的像素表示区域最大值;所有其他像素设置为 0。
2 示例
在简单示例图像中寻找区域最大值
创建一个具有若干区域最大值的简单示例图像。
bash
A = 10*ones(10,10);
A(2:4,2:4) = 22;
A(6:8,6:8) = 33;
A(2,7) = 44;
A(3,8) = 45;
A(4,9) = 44
bash
A = 10×10
10 10 10 10 10 10 10 10 10 10
10 22 22 22 10 10 44 10 10 10
10 22 22 22 10 10 10 45 10 10
10 22 22 22 10 10 10 10 44 10
10 10 10 10 10 10 10 10 10 10
10 10 10 10 10 33 33 33 10 10
10 10 10 10 10 33 33 33 10 10
10 10 10 10 10 33 33 33 10 10
10 10 10 10 10 10 10 10 10 10
10 10 10 10 10 10 10 10 10 10
查找区域最大值。请注意,结果包括在 (3,8) 处的区域最大值。
bash
regmax = imregionalmax(A)
bash
regmax = 10x10 logical array
0 0 0 0 0 0 0 0 0 0
0 1 1 1 0 0 0 0 0 0
0 1 1 1 0 0 0 1 0 0
0 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 1 0 0
0 0 0 0 0 1 1 1 0 0
0 0 0 0 0 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
3 C++实现
cpp
namespace MatlabCppCode {
bool isPeak(cv::Mat mx[], std::vector<cv::Point>& conn_points)
{
cv::Point poi_point = conn_points.back();
int row = poi_point.y;
int col = poi_point.x;
float poi_val = mx[0].at<float>(poi_point);
bool isPeakEle = true;
for (int mask_row = row - 1; mask_row >= 0 && mask_row <= row + 1 && mask_row < mx[0].rows; mask_row++) {
for (int mask_col = col - 1; mask_col >= 0 && mask_col <= col + 1 && mask_col < mx[0].cols; mask_col++) {
if (mask_row == row && mask_col == col) {
continue;
}
float conn_pt_val = mx[0].at<float>(mask_row, mask_col);
if (poi_val < conn_pt_val) {
isPeakEle = false;
break;
}
if (poi_val == conn_pt_val) {
int Peak_status = mx[1].at<uchar>(mask_row, mask_col);
if (Peak_status == 0) {
isPeakEle = false;
break;
}
else if (Peak_status == 1) {
isPeakEle = true;
break;
}
else {
cv::Point p(mask_col, mask_row);
std::vector<cv::Point>::iterator it;
it = std::find(conn_points.begin(), conn_points.end(), p);
if (it == conn_points.end()) {
conn_points.push_back(p);
isPeakEle = isPeakEle && isPeak(mx, conn_points);
}
}
}
}
if (isPeakEle == false) {
break;
}
}
return isPeakEle;
}
/**
* @brief This is equivalent to imregionalmax(img, conn = 8) of Matlab
* It takes floating point matrix, finds all local maximas and put them in 8UC1 matrix
* pls refer: https://in.mathworks.com/help/images/ref/imregionalmax.html for imregionalmax
* eg: I/P
* 10 10 10 10 10 10 10 10 10 10
10 22 22 22 10 10 44 10 10 10
10 22 22 22 10 10 10 45 10 10
10 22 22 22 10 10 10 10 44 10
10 10 10 10 10 10 10 10 10 10
10 10 10 10 10 33 33 33 10 10
10 10 10 10 10 33 33 33 10 10
10 10 10 10 10 33 33 33 10 10
10 10 10 10 10 10 10 10 10 10
10 10 10 10 10 10 10 10 10 10
* O/P
0 0 0 0 0 0 0 0 0 0
0 1 1 1 0 0 0 0 0 0
0 1 1 1 0 0 0 1 0 0
0 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 1 0 0
0 0 0 0 0 1 1 1 0 0
0 0 0 0 0 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
* @param src
* @param conn
* @return cv::Mat
*/
cv::Mat imregionalmax(cv::Mat& src)
{
//cv::Mat padded;
//cv::copyMakeBorder(src, padded, 1, 1, 1, 1, cv::BORDER_CONSTANT, cv::Scalar::all(-1));
cv::Mat padded;
cv::copyMakeBorder(src, padded, 1, 1, 1, 1, cv::BORDER_REPLICATE);
cv::Mat mx_ch1(padded.rows, padded.cols, CV_8UC1, cv::Scalar(2)); //Peak elements will be represented by 1, others by 0, initializing Mat with 2 for differentiation
cv::Mat mx[2] = { padded, mx_ch1 }; //mx[0] is padded image, mx[1] is regional maxima matrix
int mx_rows = mx[0].rows;
int mx_cols = mx[0].cols;
cv::Mat dest(mx[0].size(), CV_8UC1);
//Check each pixel for local max
for (int row = 1; row < mx_rows - 1; row++) {
for (int col = 1; col < mx_cols - 1; col++) {
std::vector<cv::Point> conn_points; //this vector holds all connected points for candidate pixel
cv::Point p(col, row);
conn_points.push_back(p);
bool isPartOfPeak = isPeak(mx, conn_points);
if (isPartOfPeak) {
mx[1].at<uchar>(row, col) = 1;
}
else {
mx[1].at<uchar>(row, col) = 0;
}
}
}
dest = mx[1](cv::Rect(1, 1, src.cols, src.rows));
return dest;
}
}
cpp
void test() {
cv::Mat A = (cv::Mat_<float>(10, 10) <<
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 22, 22, 22, 10, 10, 44, 10, 10, 10,
10, 22, 22, 22, 10, 10, 10, 45, 10, 10,
10, 22, 22, 22, 10, 10, 10, 10, 44, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 33, 33, 33, 10, 10,
10, 10, 9, 10, 10, 33, 33, 33, 10, 10,
10, 9, 9, 9, 10, 33, 33, 33, 10, 10,
10, 10, 9, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10
);
//-- 查找区域最大值
auto outFlags = MatlabCppCode::imregionalmax(A);
std::cout <<"imregionalmax:\n"<< outFlags << std::endl;
//-- 查找区域最小值
cv::Mat revDataMat(10, 10, CV_32F);
cv::normalize(A, revDataMat, 0, 1, cv::NORM_MINMAX);
revDataMat = 1 - revDataMat;
outFlags = MatlabCppCode::imregionalmax(revDataMat);
std::cout << "imregionalmin:\n" << outFlags << std::endl;
}