首页 > 其他分享 >OpenCV图像连通区域分析(14)

OpenCV图像连通区域分析(14)

时间:2023-04-16 20:01:41浏览次数:35  
标签:连通 14 int 区域分析 像素 OpenCV result 图像 轮廓

图像连通区域

图像的连通域是指图像中具有相同像素值并且位置相邻的像素组成的区域,连通域分析是指在图像中寻找出彼此互相独立的连通域并将其标记出来。提取图像中不同的连通域是图像处理中较为常用的方法,例如在车牌识别、文字识别、目标检测等领域对感兴趣区域分割与识别。一般情况下,一个连通域内只包含一个像素值,因此为了防止像素值波动对提取不同连通域的影响,连通域分析常处理的是二值化后的图像

邻域

邻域即相邻得区域,opencv中有以下两种形式得领域

  • 4-邻域:必须在水平和垂直方向上相邻,相邻的两个像素坐标必须只有一位不同而且只能相差1个像素
  • 8-邻域: 九宫格形式,相邻的两个像素坐标必须只有一位不同而且只能相差1个像素

图像邻域分析法

两遍扫描法

两遍扫描法会遍历两次图像,第一次遍历图像时会给每一个非0像素赋予一个数字标签,当某个像素的上方和左侧邻域内的像素已经有数字标签时,取两者中的最小值作为当前像素的标签,否则赋予当前像素一个新的数字标签。第一次遍历图像的时候同一个连通域可能会被赋予一个或者多个不同的标签

种子填充法

首先将所有非0像素放到一个集合中,之后在集合中随机选出一个像素作为种子像素,根据邻域关系不断扩充种子像素所在的连通域,并在集合中删除掉扩充出的像素,直到种子像素所在的连通域无法扩充,之后再从集合中随机选取一个像素作为新的种子像素,重复上述过程直到集合中没有像素(类似DFS)

连通区域操作

不带统计信息的API

int connectedComponents(InputArray image, OutputArray labels,int connectivity = 8, int ltype = CV_32S);
/*******************************************************************
*			image: 					输入二值图像
*			labels:					输出图像
*			connectivity:		     邻域
*			ltype:					 输出图深度
*********************************************************************/

带有统计信息的API

int connectedComponentsWithStats(InputArray image, OutputArray labels, OutputArray stats, OutputArray centroids,int connectivity, int ltype, int ccltype);
/*******************************************************************
*			image: 					输入二值图像
*			labels:					输出图像
*			stats:					 统计信息,包括每个组件的位置、宽、高与面积
*			centroids:				 每个组件的中心位置坐标cx, cy
*			connectivity:		     邻域
*			ltype:					 输出图深度
*			ccltype:				 连通组件算法
*********************************************************************/
//ccltype取值
enum ConnectedComponentsTypes {
    CC_STAT_LEFT   = 0, //        组件的左上角点像素点坐标的X位置             
    CC_STAT_TOP    = 1, //		  组件的左上角点像素点坐标的Y位置
    CC_STAT_WIDTH  = 2, //        组件外接矩形的宽度
    CC_STAT_HEIGHT = 3, //		  组件外接矩形的高度
    CC_STAT_AREA   = 4, //		  当前连通组件的面积(像素单位)
    CC_STAT_MAX    = 5  //        最大枚举值,仅在内部用于内存分配(可忽略)
};

综合代码

#include <iostream>
#include <string>
#include <time.h>
#include <map>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
class Connection
{
public:
	Connection() :img(imread("text.jpg",IMREAD_GRAYSCALE))
	{
		result["原图"] = img;
		threshold(img, result["阈值化"], 200, 255, THRESH_BINARY_INV);
	}
	//着色
	void DrawColor(Mat& src, Mat& result, int nCount)
	{
		vector<Vec3b> colors(nCount);
		for (int i = 1; i < nCount; i++)
		{
			colors[i] = Vec3b(rand() % 256, rand() % 256, rand() % 256);
		}
		//连通区域着色
		result = Mat::zeros(img.size(), CV_8UC3);
		for (int y = 0; y < img.rows; y++)
		{
			for (int x = 0; x < img.cols; x++)
			{
				int label = src.at<int>(y, x);
				if (label > 0 && label <= nCount)
				{
					result.at<Vec3b>(y, x) = colors[label];
				}
				if (label == 0)
				{
					result.at<Vec3b>(y, x) = Vec3b(255, 255, 255);
				}
			}
		}

	}
	void NoCount()
	{
		Mat temp;
		int nCount = connectedComponents(result["阈值化"], temp);
		//temp不能直接显示,需要转换后才能显示	
		DrawColor(temp, result["不统计"], nCount);
	}
	void Count() 
	{
		Mat stats, center, temp;
		int nCount = connectedComponentsWithStats(result["阈值化"], temp, stats, center, 8, CC_STAT_AREA);
		DrawColor(temp, result["统计"], nCount);
		//利用统计信息标记连通域
		for (int i = 1; i < nCount; i++) 
		{
			int x = stats.at<int>(i, CC_STAT_LEFT);
			int y = stats.at<int>(i, CC_STAT_TOP);
			int w = stats.at<int>(i, CC_STAT_WIDTH);
			int h = stats.at<int>(i, CC_STAT_HEIGHT);
			rectangle(result["统计"], Rect(x, y, w, h), Scalar(0, 0, 0), 2);
		}
	}
	void Show() 
	{
		for (auto& v : result) 
		{
			imshow(v.first, v.second);
		}
		waitKey(0);
	}
protected:
	Mat img;
	map<string, Mat> result;
};

int main() 
{
	srand((unsigned int)time(nullptr));
	Connection* p = new Connection;
	p->NoCount();
	p->Count();
	p->Show();
	return 0;
}

OpenCV图像连通区域分析(14)_OpenCV

OpenCV图像轮廓

图像轮廓

图像轮廓是一系列相连的点组成的曲线,代表了物体的基本外形,相对于边缘,轮廓是连续的,边缘并不全部连续。一般地,获取图像轮廓要经过下面几个步骤:

  • 读取图片
  • 灰度处理
  • 二值化处理,查找轮廓
  • 显示轮廓边缘

查找轮廓

void findContours( InputArray image, OutputArrayOfArrays contours,int mode, int method, Point offset = Point());
/*******************************************************************
*			image: 			单通道灰度图				
*			contours:	    检测到的轮廓,存储的是点坐标 	
*			mode:			轮廓检索模式
*			method:			轮廓逼近方法
*			offset:		    按照偏移量移动所有的轮廓 一般不使用
*********************************************************************/
void findContours( InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode,int method, Point offset = Point());
/*******************************************************************
*			image: 			输入单通道灰度图				
*			contours:	    检测到的轮廓,存储的是点坐标 	
*			hierarchy:		轮廓的拓扑信息
*				contours[i]包含4个hierarchy[i]元素,
*							hierarchy[i][0]:后一个轮廓
*							hierarchy[i][1]:前一个轮廓
*							hierarchy[i][2]:父轮廓
*							hierarchy[i][3]:内嵌轮廓										
*			mode:			轮廓检索模式
*			method:			轮廓逼近方法
*			offset:		    按照偏移量移动所有的轮廓 一般不使用
*********************************************************************/
//mode取值:
enum RetrievalModes {
    RETR_EXTERNAL  = 0,//只检索最外面的轮廓
    RETR_LIST      = 1,//检索所有轮廓,并保存到一条链表中
    RETR_CCOMP     = 2,//检索所有轮廓,组织为顶层(外部边界)和次层(内部边界)
    RETR_TREE      = 3,//检索所有的轮廓,并重构嵌套轮廓的整个层次
    RETR_FLOODFILL = 4 //支持CV_32SC1图像,不等于仅支持CV_8UC1图像
};
//method取值:
enum ContourApproximationModes {
    CHAIN_APPROX_NONE      = 1,	//保存所有轮廓点
    CHAIN_APPROX_SIMPLE    = 2,	//压缩水垂直对角线,只保留线的两端点
    CHAIN_APPROX_TC89_L1   = 3,	//使用teh-Chinl chain 近似算法
    CHAIN_APPROX_TC89_KCOS = 4	//使用teh-Chinl chain 近似算法
};

绘制轮廓

void drawContours( InputOutputArray image, InputArrayOfArrays contours,int contourIdx, const Scalar& color,
int thickness = 1, int lineType = LINE_8,InputArray hierarchy = noArray(),int maxLevel = INT_MAX, Point offset = Point());
/*******************************************************************
*			image: 					输出单通道灰度图	
*			contours:				所有的输入轮廓
*			contourIdx:				指定轮廓列表的索引 ID(将被绘制)
*										若为负数,则所有的轮廓将会被绘制
*			color:					绘制轮廓的颜色
*			thickness:				绘制轮廓线条的宽度
*			lineType:				线条的类型,8连通型或4连通型
*			hierarchy:				层次结构信息
*			maxLevel:				绘制轮廓的最高级别
*										 0:绘制指定轮廓
*										 1:绘制该轮廓和所有嵌套轮廓
*										 2:绘制该轮廓、嵌套轮廓子轮廓等
*			offset:					按照偏移量移动所有的轮廓
*********************************************************************/

综合代码

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
class OutLine 
{
public:
	OutLine() :img(imread("testMin.jpg", IMREAD_GRAYSCALE)) 
	{
		result["Gray"] = img;
	}
	void Show() 
	{
		for (auto& v : result) 
		{
			imshow(v.first, v.second);
		}
		waitKey(0);
	}

	//查找轮廓
	void FindOutLine() 
	{
		threshold(result["Gray"], result["Binary"], 125, 255, THRESH_BINARY);
		findContours(result["Binary"], contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
	}
	//着色
	void DrawOutLine() 
	{
		result["OutLine"] = Mat::zeros(result["Binary"].size(), CV_8UC3);
		for (int i = 0; i < contours.size(); i++) 
		{
			Scalar color = Scalar(0, 255, 0);
			//drawContours(result["OutLine"], contours, i, color, 1, 8, hierarchy);
			drawContours(result["OutLine"], contours, i, color);
		}
	}
private:
	Mat img;
	map<string, Mat> result;
	vector<vector<Point>> contours;
	vector<Vec4i> hierarchy;
};

int main() 
{
	OutLine* p = new OutLine;
	p->FindOutLine();
	p->DrawOutLine();
	p->Show();
	return 0;
}

OpenCV图像连通区域分析(14)_OpenCV_02


标签:连通,14,int,区域分析,像素,OpenCV,result,图像,轮廓
From: https://blog.51cto.com/u_15959862/6193530

相关文章

  • UVA1451
     二分平均值x,每个数减去x,   找区间S[r]-S[l]>=0,r-l>=m#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;constintN=1e5+5;#defineinf1e9intn,m,a[N];doubles[N];intchk(doublemd,intok=0){ i......
  • 14 Ray Tracing
    关键点RadientEnergyandFlux(Power)RadientIntensity1.Radiometry辐射度量学1.1Light1.1.1RadientEnergyandFlux(Power)能量与功率单位分别是焦耳、瓦特,使用flux是因为要考虑单位时间的光照结果,即光源亮度。功率的单位除了瓦特,还有流明lm(lumen)。Flux可以理解......
  • ABC214G
    首先可以考虑容斥,也就是\(ans=\sum_{i=0}^n(-1)^i\timesh_i\times(n-i)!\),\(h_i\)表示有\(i\)步限制不满足的方案数。考虑到如果对于一个排列,连\(i\rightarrowp_i\)的边会形成若干个环组成的有向图。那么对于两个相同大小的排列,连接\(p_i\rightarrowq_i\)的边同样......
  • 中小型软件企业初始管理记录20140922
    对于人数少于100人的中小型软件企业,员工的初始积极性是最重要的,企业应该考虑做到以下几点:1、薪资可以不高,但企业承诺一定要做到;2、通信费交通费必须考虑合理报销,报销过程要简单;3、加班餐费必须解决好;4、频繁加班后,需要考虑一定形式的团队建设,而且越快越好;5、员工的倒休要鼓励,不能让......
  • 4月14日多态的笔迹总结,
    1.声明的虚函数若等于零则叫纯虚函数。他不能被不重写继承,且可以代表一些实例化对象抽象的概念。2.对于虚函数接口继承的理解:普通函数是继承函数所有的东西,派生类就是为了调用这个函数而继承,而虚继承则是继承了这个函数的接口,函数的实现部分需要派生类去重写,从而达成多态。3.虚......
  • OpenCV计算相机与装甲板之间的距离
    这个距离的计算需要建立在得知平移矩阵的计算上,想要了解平移矩阵获取的可以移步:https://www.cnblogs.com/nobodyx/p/17297244.html先看一下代码#include<iostream>#include<cmath>usingnamespacestd;doubledistance(doublex1,doubley1,doublez1,doublex2,dou......
  • 2023年4月14日
    FileProvider随着Android版本越来越高,Android官方对用户数据保护力度也越来越大。Android提供FileProvider类来供应用之间共享数据。如:<pathsxmlns:android="http://schemas.android.com/apk/res/android"><files-pathname="my_images"path="images/"/>...<......
  • OpenCV图像腐蚀与膨胀(13)
    膨胀与腐蚀是数学形态学在图像处理中最基础的操作。其卷积操作非常简单,对于图像的每个像素,取其一定的邻域,计算最大值/最小值作为新图像对应像素位置的像素值。其中,取最大值就是膨胀,取最小值就是腐蚀。膨胀与腐蚀能实现多种多样的功能,主要如下:消除噪声分割出独立的图像元素,在图像中......
  • kuangbin专题一 简单搜索 罐子(POJ-3414)
    PotsTimeLimit:1000MS MemoryLimit:65536KDescriptionYouaregiventwopots,havingthevolumeofAandBlitersrespectively.Thefollowingoperationscanbeperformed:FILL(i)fillthepoti(1≤i≤2)fromthetap;DROP(i)emptythep......
  • 【剑指 Offer 】14- I. 剪绳子
    【题目】给你一根长度为n的绳子,请把绳子剪成整数长度的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1]...k[m-1]。请问k[0]*k[1]*...*k[m-1]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。示例1:输入:......