- 拥 有
- 属性像强度、灰度级
- 属 于
- 成组的像素或区域发展成更大区域
- 中文名
- 区域生长
- 外文名
- region growing
-
区域生长
2018-08-30 14:30:01区域生长算法的基本思想是将有相似性质的像素点合并到一起。对每一个区域要先指定一个种子点作为生长的起点,然后将种子点周围领域的像素点和种子点进行对比,将具有相似性质的点合并起来继...转自:https://blog.csdn.net/qq_37764129/article/details/81227091
注:本程序只能做图像分割,结果图是转自原作者的,暂时没实现该功能。
1、理论基础
区域生长算法的基本思想是将有相似性质的像素点合并到一起。对每一个区域要先指定一个种子点作为生长的起点,然后将种子点周围领域的像素点和种子点进行对比,将具有相似性质的点合并起来继续向外生长,直到没有满足条件的像素被包括进来为止。这样一个区域的生长就完成了。这个过程中有几个关键的问题:
a> 给定种子点(种子点如何选取?)
种子点的选取很多时候都采用人工交互的方法实现,也有用其他方式的,比如寻找物体并提取物体内部点作为种子点。
b> 确定在生长过程中能将相邻像素包括进来的准则
灰度图像的差值;彩色图像的颜色等等。都是关于像素与像素间的关系描述。
c> 生长的停止条件
2、灰度差值的区域生长算法实现
算法实现的步骤:
a> 创建一个空白的图像(全黑);
b> 将种子点存入vector中,vector中存储待生长的种子点;
c> 依次弹出种子点并判断种子点如周围8领域的关系(生长规则),相似的点则作为下次生长的种子点;
d> vector中不存在种子点后就停止生长。
-
#include <opencv2\highgui\highgui.hpp>
-
#include <iostream>
-
#include "math.h"
-
using namespace cv;
-
using namespace std;
-
Mat RegionGrow(Mat src, Point2i pt, int th)
-
{
-
Point2i ptGrowing; //待生长点位置
-
int nGrowLable = 0; //标记是否生长过
-
int nSrcValue = 0; //生长起点灰度值
-
int nCurValue = 0; //当前生长点灰度值
-
Mat matDst = Mat::zeros(src.size(), CV_8UC1); //创建一个空白区域,填充为黑色
-
//生长方向顺序数据
-
int DIR[8][2] = { { -1, -1 }, { 0, -1 }, { 1, -1 }, { 1, 0 }, { 1, 1 }, { 0, 1 }, { -1, 1 }, { -1, 0 } };
-
Vector<Point2i> vcGrowPt; //生长点栈
-
vcGrowPt.push_back(pt); //将生长点压入栈中
-
matDst.at<uchar>(pt.y, pt.x) = 255; //标记生长点
-
nSrcValue = src.at<uchar>(pt.y, pt.x); //记录生长点的灰度值
-
while (!vcGrowPt.empty()) //生长栈不为空则生长
-
{
-
pt = vcGrowPt.back(); //取出一个生长点
-
vcGrowPt.pop_back();
-
//分别对八个方向上的点进行生长
-
for (int i = 0; i<9; ++i)
-
{
-
ptGrowing.x = pt.x + DIR[i][0];
-
ptGrowing.y = pt.y + DIR[i][1];
-
//检查是否是边缘点
-
if (ptGrowing.x < 0 || ptGrowing.y < 0 || ptGrowing.x >(src.cols - 1) || (ptGrowing.y > src.rows - 1))
-
continue;
-
nGrowLable = matDst.at<uchar>(ptGrowing.y, ptGrowing.x); //当前待生长点的灰度值
-
if (nGrowLable == 0) //如果标记点还没有被生长
-
{
-
nCurValue = src.at<uchar>(ptGrowing.y, ptGrowing.x);
-
if (abs(nSrcValue - nCurValue) < th) //在阈值范围内则生长
-
{
-
matDst.at<uchar>(ptGrowing.y, ptGrowing.x) = 255; //标记为白色
-
vcGrowPt.push_back(ptGrowing); //将下一个生长点压入栈中
-
}
-
}
-
}
-
}
-
return matDst.clone();
-
}
-
int main() //区域生长
-
{
-
Mat src = imread("E:\\QT text\\image processing\\delineation\\image\\1.jpg");
-
namedWindow("原图", 0);
-
imshow("原图", src);
-
Point pt = (514,510); //待生长点位置
-
int th = 10;
-
src = RegionGrow(src, pt, th);
-
namedWindow("RegionGrow", 0);
-
imshow("RegionGrow", src);
-
waitKey(0);
-
return 0;
-
}
3、算法效果
贴图看看使用该算法的图像处理效果:
首先对原图像进行二值化:
得到种子点的方法这里就不用介绍了,这个不是该算法的重点。得到两个种子点(左右肺),分别使用区域生长算法得到左右肺区,然后与原图进行与运算,得到结果:
To:博乐评论中提到的原始区域生长的算法思想。原始区域生长中一般有四领域的生长和八领域的生长两种方式,基本思想和该算法是一致的。这个算法也是博主在以前没有使用opencv的程序中修改得来的。
转自:https://blog.csdn.net/robin__chou/article/details/50071313
相关博客:
区域生长基础理论及代码:https://blog.csdn.net/gaohuazhao/article/details/51100429
-
-
PCL 区域生长分割
2020-07-25 20:45:48基于区域生长的分割一、算法原理
1、算法流程
根据点的曲率值对点云进行排序,曲率最小的点叫做初始种子点,
(1)区域生长算法从曲率最小的种子点开始生长,初始种子点所在区域为最平滑区域,从初始种子点所在的区域开始生长可减小分割片段的总数,从而提高算法的效率。
(2)设置一空的聚类区域C和空的种子点序列Q,聚类数组L。
(3)选好初始种子点,将其加入种子点序列Q中,并搜索该种子点的领域点,计算每一个领域点法线与种子点法线之间的夹角,小于设定的平滑阀值时,将领域点加入到C中,同时判断该领域点的曲率值是否小于曲率阀值,将小于曲率阈值的领域点加入种子点序列Q中,在邻域点都判断完成后,删除当前种子点,在Q中重新选择新的种子点重复上述步骤,直到Q中序列为空,一个区域生长完成,将其加入聚类数组L中。
(4)利用曲率值从小到大排序,顺序选择输入点集 的点作为种子点加入到种子点序列中,重复以上生长的步骤。2、算法概述
- 官网document里的介绍:Region growing segmentation
2、代码图解
二、代码实现
#include <iostream> #include <vector> #include <pcl/point_types.h> #include <pcl/io/pcd_io.h> #include <pcl/search/search.h> #include <pcl/search/kdtree.h> #include <pcl/features/normal_3d.h> #include <pcl/visualization/cloud_viewer.h> #include <pcl/filters/passthrough.h> #include <pcl/segmentation/region_growing.h>//区域生长 #include <pcl/console/print.h> #include <pcl/console/parse.h> #include <pcl/console/time.h> #include <windows.h> #include <stdio.h> #include <psapi.h> void PrintMemoryInfo( ) { HANDLE hProcess; PROCESS_MEMORY_COUNTERS pmc; hProcess=GetCurrentProcess(); printf( "\nProcess ID: %u\n", hProcess ); //输出进程使用的内存信息 if (NULL == hProcess) return; if ( GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)) ) { printf( "\tPageFaultCount: 0x%08X\n", pmc.PageFaultCount ); printf( "\tPeakWorkingSetSize: 0x%08X\n", pmc.PeakWorkingSetSize ); printf( "\tWorkingSetSize: 0x%08X\n", pmc.WorkingSetSize ); printf( "\tQuotaPeakPagedPoolUsage: 0x%08X\n", pmc.QuotaPeakPagedPoolUsage ); printf( "\tQuotaPagedPoolUsage: 0x%08X\n", pmc.QuotaPagedPoolUsage ); printf( "\tQuotaPeakNonPagedPoolUsage: 0x%08X\n", pmc.QuotaPeakNonPagedPoolUsage ); printf( "\tQuotaNonPagedPoolUsage: 0x%08X\n", pmc.QuotaNonPagedPoolUsage ); printf( "\tPagefileUsage: 0x%08X\n", pmc.PagefileUsage ); printf( "\tPeakPagefileUsage: 0x%08X\n", pmc.PeakPagefileUsage ); } CloseHandle( hProcess ); } using namespace pcl::console; int main (int argc, char** argv) { if(argc<2) { std::cout<<".exe xx.pcd -kn 50 -bc 0 -fc 10.0 -nc 0 -st 30 -ct 0.05"<<endl; return 0; }//如果输入参数小于1个,输出提示 time_t start,end,diff[5],option; start = time(0); int K=50; //设置默认输入参数 bool Bool_Cuting=false;//设置默认输入参数 float far_cuting=10,near_cuting=0,SmoothnessThreshold=30.0,CurvatureThreshold=0.05;//设置默认输入参数 parse_argument (argc, argv, "-kn", K); parse_argument (argc, argv, "-bc", Bool_Cuting); parse_argument (argc, argv, "-fc", far_cuting); parse_argument (argc, argv, "-nc", near_cuting); parse_argument (argc, argv, "-st", SmoothnessThreshold); parse_argument (argc, argv, "-ct", CurvatureThreshold);//设置输入参数方式 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); if ( pcl::io::loadPCDFile <pcl::PointXYZ> (argv[1], *cloud) == -1) { std::cout << "Cloud reading failed." << std::endl; return (-1); }//--------------加载点云数据------------------------------- end = time(0); diff[0] = difftime (end, start); PCL_INFO ("\Loading pcd file takes(seconds): %d\n", diff[0]); //----------------法线估计---------------------------------- pcl::search::Search<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>); pcl::PointCloud <pcl::Normal>::Ptr normals (new pcl::PointCloud <pcl::Normal>); pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> n; n.setSearchMethod (tree);//设置搜索方法 n.setInputCloud (cloud);//设置法线估计对象输入点集 n.setKSearch (K);// 设置用于法向量估计的k近邻数目 n.compute (*normals);//计算并输出法向量 end = time(0); diff[1] = difftime (end, start)-diff[0]; PCL_INFO ("\Estimating normal takes(seconds): %d\n", diff[1]); //-----------------直通滤波---(可选操作)-------------------- pcl::IndicesPtr indices (new std::vector <int>);//创建一组索引 if(Bool_Cuting)//判断是否需要直通滤波 { pcl::PassThrough<pcl::PointXYZ> pass;//设置直通滤波器对象 pass.setInputCloud (cloud);//设置输入点云 pass.setFilterFieldName ("z");//设置指定过滤的维度 pass.setFilterLimits (near_cuting, far_cuting);//设置指定纬度过滤的范围 pass.filter (*indices);//执行滤波,保存滤波结果在上述索引中 } //-----------------------区域生长---------------------------- pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg;//创建区域生长分割对象 reg.setMinClusterSize (50);//设置一个聚类需要的最小点数 reg.setMaxClusterSize (1000000);//设置一个聚类需要的最大点数 reg.setSearchMethod (tree);//设置搜索方法 reg.setNumberOfNeighbours (30);//设置搜索的临近点数目 reg.setInputCloud (cloud);//设置输入点云 if(Bool_Cuting)reg.setIndices (indices);//通过输入参数设置,确定是否输入点云索引 reg.setInputNormals (normals);//设置输入点云的法向量 reg.setSmoothnessThreshold (SmoothnessThreshold / 180.0 * M_PI);//设置平滑阈值 reg.setCurvatureThreshold (CurvatureThreshold);//设置曲率阈值 std::vector <pcl::PointIndices> clusters; reg.extract (clusters);//获取聚类的结果,分割结果保存在点云索引的向量中。 end = time(0); diff[2] = difftime (end, start)-diff[0]-diff[1]; PCL_INFO ("\Region growing takes(seconds): %d\n", diff[2]); std::cout << "Number of clusters is equal to " << clusters.size () << std::endl;//输出聚类的数量 std::cout << "First cluster has " << clusters[0].indices.size () << " points." << endl;//输出第一个聚类的数量 std::cout << "These are the indices of the points of the initial" << std::endl << "cloud that belong to the first cluster:" << std::endl; //---------------------------保存聚类的点云----------------------------- /*int j = 0; for (std::vector<pcl::PointIndices>::const_iterator it = clusters.begin(); it != clusters.end(); ++it) { pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster(new pcl::PointCloud<pcl::PointXYZ>); for (std::vector<int>::const_iterator pit = it->indices.begin(); pit != it->indices.end(); pit++) cloud_cluster->points.push_back(cloud->points[*pit]); cloud_cluster->width = cloud_cluster->points.size(); cloud_cluster->height = 1; cloud_cluster->is_dense = true; std::cout << "PointCloud representing the Cluster: " << cloud_cluster->points.size() << " data points." << std::endl; std::stringstream ss; ss << "cloud_cluster_" << j << ".pcd"; pcl::io::savePCDFileASCII(ss.str(), *cloud_cluster); cout << ss.str() << "Saved" << endl; j++; } */ PrintMemoryInfo(); //--------------------进行可视化------------------------------------------ pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = reg.getColoredCloud (); //保存附加颜色的点云 //pcl::io::savePCDFileASCII("colored_pointCloud.pcd",*colored_cloud); pcl::visualization::CloudViewer viewer ("区域生长分割方法"); viewer.showCloud(colored_cloud); while (!viewer.wasStopped ()) { } return (0); }
三、结果展示
-
PCL 基于颜色的区域生长分割
2020-07-25 21:40:04基于颜色的区域生长分割一、算法原理
1、原理概述
该算法与区域生长算法一样,是基于同一策略之上的,与区域生长相比,该算法主要有两处不同:第一,该算法用颜色代替了法线,去掉了点云规模上 限的限制。可以认为,同一个颜色且挨得近,是一类的可能性很大,不需要上限来限制。所以这种方式比较适合用于室内场景分割,尤其是复杂室内场景,颜色分割可以轻松的将连续的场景点云变成不同的物体。哪怕是高低不平的地面,没法用采样一致分割器抽掉,颜色分割算法同样能完成分割任务。第二,利用合并算法来控制过分割或欠分割。分割过程中,若两个相邻聚类的平均颜色相差较少,则将这两个聚类合并。然后进行第二步合并,在此步骤中,检查每一个聚类所包含的点的数量,如果这个数量小于用户定义的值,则当前这个聚类与其相近邻聚类合并在一起。
1、算法步骤
(1)分割,当前种子点和领域点之间色差小于色差阀值的视为一个聚类;
(2)合并,聚类之间的色差小于色差阀值和并为一个聚类,且当前聚类中点的数量小于聚类点数量的与最近的聚类合并在一起;3、代码图解
二、代码实现
#include <iostream> #include <vector> #include <pcl/point_types.h> #include <pcl/io/pcd_io.h> #include <pcl/search/search.h> #include <pcl/search/kdtree.h> #include <pcl/visualization/cloud_viewer.h> #include <boost/thread/thread.hpp> #include <pcl/filters/passthrough.h> #include <pcl/segmentation/region_growing_rgb.h> using namespace std; int main(int argc, char** argv) { pcl::PointCloud <pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud <pcl::PointXYZRGB>); if (pcl::io::loadPCDFile <pcl::PointXYZRGB>("region_growing_rgb_tutorial.pcd", *cloud) == -1) { cout << "Cloud reading failed." << endl; return (-1); } //-------------------------直通滤波---------------------------- pcl::IndicesPtr indices(new std::vector <int>); pcl::PassThrough<pcl::PointXYZRGB> pass; pass.setInputCloud(cloud); pass.setFilterFieldName("z"); pass.setFilterLimits(0.0, 1.0); pass.filter(*indices); //-----------------可以同时用颜色测试和法线测试这两种手段----------------------- pcl::search::Search <pcl::PointXYZRGB>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZRGB>); pcl::RegionGrowingRGB<pcl::PointXYZRGB> reg; reg.setInputCloud(cloud); reg.setIndices(indices); reg.setSearchMethod(tree); reg.setDistanceThreshold(10);//设置距离阈值,用于聚类相邻点搜索 reg.setPointColorThreshold(6);//设置两点颜色阈值 reg.setRegionColorThreshold(5);//设置两类区域颜色阈值 reg.setMinClusterSize(600);//设置一个聚类的最少点数目 vector <pcl::PointIndices> clusters; reg.extract(clusters);//获取聚类的结果,分割结果保存在点云索引的向量中 //------------对不同的聚类分割结果,随机赋予颜色--------------------------- pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = reg.getColoredCloud(); //----------------------------可视化---------------------------------------- pcl::visualization::CloudViewer viewer("Cluster viewer"); viewer.showCloud(colored_cloud); while (!viewer.wasStopped()) { } return 0; }
三、结果展示
1、参数设置
2、可视化
-
4.1图像分割之区域生长法
2018-08-04 16:37:39传统的区域分割方法有区域生长和区域分裂与合并, 其中最基础的是区域生长法。 区域生长法 区域生长是根据事先定义的准则将像素或者子区域聚合成更大区域的过程。其基本思想是从一组生长点开始...我们将讨论以区域为基础的图像分割处理技术。传统的区域分割方法有区域生长和区域分裂与合并, 其中最基础的是区域生长法。
区域生长法
区域生长是根据事先定义的准则将像素或者子区域聚合成更大区域的过程。其基本思想是从一组生长点开始(生长点可以是单个像素,也可以是某个小区域),将与该生长点性质相似的相邻像素或者区域与生长点合并,形成新的生长点,重复此过程直到不能生长为止。生长点和相似区域的相似性判断依据可以是灰度值、纹理、颜色等图像信息。所以区域生长算法关键有三个:
1、选择合适的生长点
2、确定相似性准则即生长准则
3、确定生长停止条件
下面给出一个区域生长的实例:图(a)为原始图像,数字表示像素的灰度。以灰度值为8的像素为初始的生长点,记为f(i,j)。在8邻域内,生长准则是待测点灰度值与生长点灰度值相差为1或0.那么图(b)是第一次区域生长后,f(i-1,j)、f(i,j-1)、f(i,j+1)和生长点灰度值相差都是1,因而被合并。图©是第二次生长后,f(i+1,j)被合并。图(d)为第三次生长后,f(i+1,j-1)、f(i+2,j)被合并,至此,已经不存在满足生长准则的像素点,生长停止。
示例演示
我们实现一个功能,鼠标选择一个初始生长点,生长准则是待测点灰度值与初始生长点灰度值差的绝对值不大于8。示例代码中regionGrow函数参考了《数字图像处理与机器视觉》第九章第五节,regionGrowFast函数是优化过的实现,代码如下:
cv::Mat MainWindow::regionGrowFast(const cv::Mat &src, const cv::Point2i seed, int throld) { //convert src to gray for getting gray value of every pixel cv::Mat gray; cv::cvtColor(src,gray, cv::COLOR_RGB2GRAY); // set every pixel to black cv::Mat result = cv::Mat::zeros(src.size(), CV_8UC1); if((seed.x < 0) || (seed.y < 0)) return result; result.at<uchar>(seed.y, seed.x) = 255; //gray value of seed int seed_gray = gray.at<uchar>(seed.y, seed.x); //grow direction sequenc int grow_direction[8][2] = {{-1,-1}, {0,-1}, {1,-1}, {1,0}, {1,1}, {0,1}, {-1,1}, {-1,0}}; //seeds collection std::vector<cv::Point2i> seeds; seeds.push_back(seed); //start growing while(! seeds.empty()){ //get a seed cv::Point2i current_seed = seeds.back(); seeds.pop_back(); for(int i = 0; i < 8; ++i){ cv::Point2i neighbor_seed(current_seed.x + grow_direction[i][0], current_seed.y + grow_direction[i][1]); //check wether in image if(neighbor_seed.x < 0 || neighbor_seed.y < 0 || neighbor_seed.x > (gray.cols-1) || (neighbor_seed.y > gray.rows -1)) continue; int value = gray.at<uchar>(neighbor_seed.y, neighbor_seed.x); if((result.at<uchar>(neighbor_seed.y, neighbor_seed.x) == 0) && (abs(value - seed_gray) <= throld)){ result.at<uchar>(neighbor_seed.y, neighbor_seed.x) = 255; seeds.push_back(neighbor_seed); } } } return result; }
运行结果:
-
区域生长法MATLAB
2020-07-08 20:01:09区域生长算法的设计主要由以下三点:生长种子点的确定,区域生长的条件,区域生长停止的条件。 代码采用交互的方式,用鼠标选取合适的种子点,搜索种子点8邻域内的像素。 -
区域生长算法程序
2018-03-19 15:07:03区域生长的matlab程序。可以用来进行学习区域生长算法时使用, -
python 区域生长算法_多种子的区域生长算法
2020-12-24 12:16:45摘要:多种子的区域生长算法,基于C++编写。关键字:图像处理, 种子生长, 区域生长1. 题外话最近需要找一种简单对图像进行分割的算法,作为后续算法的前处理阶段。最开始想到的是聚类,但是聚类会有分割后不保证连通... -
Python简单实现区域生长方式
2020-12-23 02:34:04区域生长是一种串行区域分割的图像分割方法。区域生长是指从某个像素出发,按照一定的准则,逐步加入邻近像素,当满足一定的条件时,区域生长终止。区域生长的好坏决定于1.初始点(种子点)的选取。2.生长准则。3.... -
区域生长算法实现
2017-07-11 15:45:48区域生长算法实现简单历程 -
区域生长代码
2016-01-06 10:58:02区域生长算法,适合学习。需要vs以及opencv2的开发环境,运行成功后点击图像选择种子点即可 -
区域生长算法
2015-04-19 17:15:55区域生长算法的简单实现,人工选取种子,对二值图像的前景进行分割。 -
三维区域生长
2018-01-23 22:00:29区域生长(region growing)是指将成组的像素或区域发展成更大区域的过程。从种子点的集合开始,从这些点的区域增长是通过将与每个种子点有相似属性像强度、灰度级、纹理颜色等的相邻像素合并到此区域。 -
区域生长算法 python代码_OpenCV:区域生长法实现
2020-12-15 18:20:04示例程序:OpenCV没有自带区域生长函数;为了说明区域是如何生长的,#include #include #include #include using namespace std;using namespace cv;void RegionGrowing(Mat srcImg,Mat& dstImg,Point pt,int th... -
区域生长matlab代码
2015-04-16 15:07:42区域生长的代码,matlab实现 手动点选种子点,根据设置的阈值(可更改),进行区域生长。 -
区域生长法
2018-06-16 21:07:56区域生长的基本思想是将具有相似性质的像素集合起来构成区域。具体先对每个需要分割的区域找一个种子像素作为生长的起点,然后将种子像素周围邻域中与种子像素具有相同或相似性质的像素(根据某种事先确定的生长或... -
区域生长算法,种子点选取
2021-01-30 13:30:18区域生长种子点选取,种子点变换生长,种子点变换生长,种子点变换生长,种子点变换生长,种子点变换生长,种子点变换生长,种子点变换生长 -
opencv区域生长/区域扩散
2020-01-09 14:48:16区域生长:就是以某个像素值进行扩散,查找颜色相近的范围区域。 这里主要介绍四种方法:固定灰度值、动态灰度值、固定RGB值、动态RGB值。这四种方法对应不同图片。经测试效果可以 1.固定灰度值区域生长 //固定... -
matlab图像区域生长
2017-06-20 23:26:12MATLAB编写的图像区域生长函数(附原图像和结果),用于二值图像的分割,由于for循环调用较多,建议先认真阅读,谨慎运行。 -
区域生长法MATLAB版本程序代码
2021-01-14 11:00:31区域生长法MATLAB版本程序代码,需要把图像名字改成程序里一致的 区域生长法MATLAB版本程序代码,需要把图像名字改成程序里一致的 -
区域生长法分割
2020-06-24 10:48:10区域分割区域生长法 区域生长法 区域生长法的基本思想就是将具有相似性的像素集合起来形成一个区域。 具体做法就是,首先选择一个种子点,通过比较种子点邻域的相似性,将邻域中满足相似性准则的像素归入种子点所在... -
基于区域生长图像分割
2016-04-16 14:32:40基于区域生长图像分割