块标记c++代码

上研究生时写的代码,为了防止时间久了丢失,将它贴到网上。

头文件:

#include "cv.h"
#include "cxcore.h"
#include "highgui.h"

#include <vector>
using namespace std;

class ConCompLabel
{
private:
	//传入参数(同时也是传出参数,最终的标记图)
	IplImage* bwImg;

	//内部参数
	int bwHeight;
	int bwWidth;
	int boundWidth;				//边界宽度
	vector<int> labelTabel;		//标记表
	int labelNum;				//当前的最大标记号
	IplImage* boundImg;			//包含边框的图像

	//传出参数
	vector<int> compSize;	//标记完后,各连接部件的面积
	int maxSize;			//最大块的面积
	int maxLabel;			//最大块的标号
	IplImage* maxImg;		//只包含最大块的图像
	CvRect maxCompRect;		//最大块的外接矩形

public:
	ConCompLabel(IplImage* bwImg0);
	~ConCompLabel();
	int option();

	int getLabelImg() const {return bwImg;}
	int getMaxImg() const {return maxImg;}
	CvRect getMaxCompRect() const {return maxCompRect;}

private:
	int addBound();
	int removeBound();
	int scan();
	int adjast();	//可得到最终的标记图像
	int link(int leftLabel, int rightLabel);

	int calcCompSize();
	int selectMaxImg();
	int calcmaxCompRect();
};


cpp文件:

#include "ConCompLabel.h"

ConCompLabel::ConCompLabel(IplImage* bwImg0)
{
	bwImg = bwImg0;
	boundWidth = 1;

	bwHeight = bwImg0->height;
	bwWidth = bwImg0->width;

	labelNum = 0;	//!!务必清零
	labelTabel.push_back(labelNum);	//将向量的第一个元素的标记变为0

	//为了处理边界问题,在源图像周围加一圈
	boundImg = cvCreateImage(cvSize(width + 2 * boundWidth, 
		bwHeight + 2 * boundWidth), IPL_DEPTH_8U, 1);
	cvZero(boundImg);

	maxImg = cvCreateImage(cvSize(width, bwHeight), IPL_DEPTH_8U, 1);
	cvZero(maxImg);

	compSize.push_back(0);	//没有标记为0的块,因此标记为0的像素总数为0
	maxSize = 0;

}

ConCompLabel::~ConCompLabel()
{
	cvReleaseImage(&boundImg);
	cvReleaseImage(&maxImg);
}

//给图像增加一圈背景像素,以处理边界问题
//传入图像必须为8位灰度的

int ConCompLabel::addBound()
{
	for (int i = boundWidth; i < bwHeight + boundWidth; i++)
	{
		for (int j = boundWidth; j < width + boundWidth; j++)
		{
			CV_IMAGE_ELEM(boundImg, uchar, i, j) = 
				CV_IMAGE_ELEM(bwImg, uchar, i - boundWidth, j - boundWidth);			
		}
	}

	return 0;
}

//参考文献:Suzuki, Fast connected component labeling, pattern recognition, 42(2009), 1977-1987.

int ConCompLabel::scan()
{
	for (int i = boundWidth; i < bwHeight + boundWidth; i++)
	{
		for (int j = boundWidth; j < width + boundWidth; j++)
		{
			if (CV_IMAGE_ELEM(boundImg, uchar, i, j))
			{
				int c1 = CV_IMAGE_ELEM(boundImg, uchar, i, j - 1);
				int c2 = CV_IMAGE_ELEM(boundImg, uchar, i - 1, j - 1);
				int c3 = CV_IMAGE_ELEM(boundImg, uchar, i - 1, j);
				int c4 = CV_IMAGE_ELEM(boundImg, uchar, i - 1, j + 1);

				if (c3)
					CV_IMAGE_ELEM(boundImg, uchar, i, j) = c3;
				else if (c1)
				{
					CV_IMAGE_ELEM(boundImg, uchar, i, j) = c1;
					if (c4)
					{
						link(c1, c4);
					}
				}
				else if (c2)
				{
					CV_IMAGE_ELEM(boundImg, uchar, i, j) = c2;
					if (c4)
					{
						link(c2, c4);
					}
				}
				else if (c4)
					CV_IMAGE_ELEM(boundImg, uchar, i, j) = c4;
				else
				{
					//在final_label中添加新的标记
					CV_IMAGE_ELEM(boundImg, uchar, i, j) = ++labelNum;	
					labelTabel.push_back(labelNum);
				}
			}			
		}//for j
	}//for i

	return 0;
}

//第二次扫描

int ConCompLabel::adjast()
{
	for (int i = boundWidth; i < bwHeight + boundWidth; i++)
	{
		for (int j = boundWidth; j < width + boundWidth; j++)
		{
			if (CV_IMAGE_ELEM(boundImg, uchar, i, j))
			{
				CV_IMAGE_ELEM(boundImg, uchar, i, j) =
				labelTabel[CV_IMAGE_ELEM(boundImg, uchar, i, j)];
			}//if

		}//for j
	}//for i

	return 0;
}

int ConCompLabel::removeBound()
{
	for (int i = boundWidth; i < bwHeight + boundWidth; i++)
	{
		for (int j = boundWidth; j < width + boundWidth; j++)
		{
			CV_IMAGE_ELEM(bwImg, uchar, i - boundWidth, j - boundWidth) = 
				CV_IMAGE_ELEM(boundImg, uchar, i, j);			
		}
	}

	return 0;
}

//两种标记之间存在连接时,调整标记表

int ConCompLabel::link(int leftLabel, int rightLabel)
{
	int srcLabel = labelTabel[leftLabel];
	int srcLabel = labelTabel[rightLabel];

	//此时,c2和c4之间存在连接,将final_label中标记为c2的全改为c4
	for (int t = 1; t <= labelTabel.size(); t++)	
	{								
		if (labelTabel[t] == srcLabel)
			labelTabel[t] = srcLabel;
	}

	return 0;
}

//计算各连接块的面积

int ConCompLabel::calcCompSize()
{
	//统计各块的面积
	for (int i = 0; i < bwHeight; i++)
		for (int j = 0; j < bwWidth; j++)
		{
			int index = CV_IMAGE_ELEM(bwImg, uchar, i, j);
			if (index)
			{
				//如果标记值在面积向量中尚未出现,则入栈,相应面积值为0
				if (index > compSize.size() - 1)
				{
					for (int t = compSize.size(); t <= index; t++)
					{
						compSize.push_back(0);
					}
				}

				//面积值加1
				compSize[index] ++;	
			}
		}

		//搜寻最大面积的块
		maxSize = 0;
		for (int i = 1; i <= compSize.size(); i++)
		{
			if (compSize[i] > maxSize)
			{
				maxSize = compSize[i];
				maxLabel = i;
			}
		}


	return 0;
}

//滤除其它块,只保留最大面积块

int ConCompLabel::selectMaxImg()
{
	for (int i = 0; i < bwHeight; i++)
		for (int j = 0; j < bwWidth; j++)
			CV_IMAGE_ELEM(maxImg, uchar, i, j) = 
			(CV_IMAGE_ELEM(bwImg, uchar, i, j) == maxLabel) ? 255 : 0;

	return 0;

}

//计算最大连接块的外接矩形

int ConCompLabel::calcmaxCompRect()
{
	int minX = bwWidth - 1;
	int maxX = 0;
	int minY = bwHeight - 1;
	int maxY = 0;

	for (int i = 0; i < bwHeight; i++)
	{
		for (int j = 0; j < bwWidth; j++)
		{
			if (CV_IMAGE_ELEM(img_max_block, uchar, i, j))
			{
				minX = j < minX ? j : minX;
				maxX = j > maxX ? j : maxX;

				minY = i < minY ? i : minY;
				maxY = i > maxY ? i : maxY;

			}// if
		}// for j
	}//for i

	maxCompRect.x = minX;
	maxCompRect.y = minY;
	maxCompRect.width = maxX - minX + 1;
	maxCompRect.height = maxY - minY + 1;

	return 0;
}

int ConCompLabel::option()
{
	addBound();
	scan();
	adjast();
	removeBound();

	calcCompSize();
	selectMaxImg();
	calcmaxCompRect();

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值