图像处理之区域生长算法(C++)
前言
区域生长算法是传统图像分割算法的基础,使用C++实现该算法。
一、算法原理
1.基本思想
区域生长算法的基本思想是将有相似性质的像素点合并到一起。
- 对每一个区域要先指定一个种子点P0作为生长的起点
- 然后将种子点周围领域(四邻域或者八邻域)的像素点Pi和种子点进行对比
- 将具有相似性质的点合并起来继续向外生长,直到没有满足条件的像素被包括进来为止。
2.关键问题
- 种子点如何选取
如何正确地选择代表区域的起始点或点集 - 相似性质的确定
灰度图像的灰度值;彩色图像的颜色;图像的纹理特征等 - 生长的停止条件
阈值的确定
3.实现步骤
- 创建一个空白的图像作为结果图
- 将种子点放入队列deque中,deque中存储待生长的种子点
- 依次弹出种子点并判断种子点如周围八邻域的关系(生长规则),相似的点作为下次生长的种子点
- deque中不存在种子点后就停止生长
二、代码实现
#include <opencv.hpp>
#include <iostream>
/*
* param const cv::Mat& src 输入图像
* param cv::Mat& dst 输出图像
* param cv::Point pt 种子点
* param int thresh 阈值
* brief 区域生长算法
*/
void regionGrow(const cv::Mat& src, cv::Mat& dst, cv::Point pt, int thresh)
{
// 1.创建一个空白图像
dst = cv::Mat::zeros(src.size(), CV_8UC1);
// 2.将种子点放入deque中,deque中存储待生长的种子点
std::deque<cv::Point> pts;
pts.push_back(pt);
dst.at<uchar>(pt.y, pt.x) = 255; //255表示该点已经生长
int srcValue = src.at<uchar>(pt.y, pt.x); // 种子点对应的像素值
// 3.依次弹出种子点并判断种子点与周围八邻域点的关系(生长规则),相似的点添加到deque作为下次生长的种子点
int dir[8][2] = { {-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0} };
while (pts.size())
{
// 3.1 弹出种子点,尾进尾出(或者头进头出)
pt = pts.back();
pts.pop_back();
// 3.2判断种子点与周围八邻域点的关系
for (int i = 0; i < 8; i++)
{
int x = pt.x + dir[i][0];
int y = pt.y + dir[i][1];
// 判断邻域点是否超出图像边界
if (x >= src.cols || x < 0 || y >= src.rows || y < 0)
continue;
// 判断该点是否已经生长
int curValue = src.at<uchar>(y, x);
if (dst.at<uchar>(y, x) == 0)
{
if (abs(srcValue-curValue) < thresh) // 此处假定灰度图像的差值的阈值作为生长停止条件
{
pts.push_back(cv::Point(x, y));
dst.at<uchar>(y, x) = 255;
}
}
}
}
}
int main()
{
// 读取图片
std::string filepath = "F://work_study//algorithm_demo//regionGrow_test.jpg";
cv::Mat src = cv::imread(filepath, cv::IMREAD_GRAYSCALE);
if (src.empty())
{
return -1;
}
cv::Mat dst;
regionGrow(src, dst, cv::Point(src.cols / 2, src.rows / 2), 10);
//regiongrow(src, dst, cv::Point(src.cols / 2, src.rows / 2), 10);
// 保存图片
cv::imwrite("dst.jpg", dst);
system("pause");
return 0;
}
总结
使用C++实现了图像处理区域生长算法,欢迎阅读并提出改进意见。