种子填充法提取连通区域C++和Python实现

在图像处理中经常需要对连通区域进行操作,而连通区域的提取一般有两步法和种子填充法,方法不再介绍,比较简单,下面是自己实现的过程,特此记录!

#include<iostream>
#include<algorithm>
#include<opencv2/opencv.hpp>
#include<map>
using namespace std;
using namespace cv;
int label = 0;// 联通域的标记
int area = 0;//连通区域
vector<Point2d>p;//保存标号
Point2d seed;
map<int, Point3d>dic;//里面保存每个联通域的随机颜色
map<int, int>label_area; //联通域面积
map<int, Rect> rect;//外接矩形
Rect l;
int row_min = 0;
int row_max = 0;
int col_min = 0;
int col_max = 0;
RNG png;
void color(Mat imm);
void seedfill(Mat im)
{
	for (int i = 0; i < im.rows; i++)
	{
		uchar *data = im.ptr<uchar>(i);
		for (int j = 0; j < im.cols; j++)
		{
			if (data[j] == 255)
			{
				area = 0;
				++label;
				++area;
				dic[label] = Point3d(png.uniform(0, 255), png.uniform(0, 255), png.uniform(0, 255));//字典将颜色和label对应起来
				data[j] = label;//开始标号
				p.push_back(Point2d(i, j));
				seed = Point2d(i, j);
				col_min = j;
				col_max = j;
				row_min = i;
				row_max = i;//定义label的外接矩形

				while (!p.empty())
				{
					if (im.at<uchar>(seed.x, seed.y + 1) == 255)
					{
						im.at<uchar>(seed.x, seed.y + 1) = label;
						p.push_back(Point2d(seed.x, seed.y + 1));
						++area;
						if (col_max < seed.y + 1)
						{
							col_max = seed.y + 1;
						}
					}
					if (im.at<uchar>(seed.x+1, seed.y ) == 255)
					{
						im.at<uchar>(seed.x+1,seed.y ) = label;
						p.push_back(Point2d(seed.x+1, seed.y));
						++area;
						if (row_max < seed.x + 1)
						{
							row_max = seed.x + 1;
						}
					}
					if (im.at<uchar>(seed.x, seed.y -1) == 255)
					{
						im.at<uchar>(seed.x, seed.y - 1) = label;
						p.push_back(Point2d(seed.x, seed.y - 1));
						++area;
						if (col_min > seed.y- 1)
						{
							col_min = seed.y - 1;
						}
					}
					if (im.at<uchar>(seed.x-1, seed.y ) == 255)
					{
						im.at<uchar>(seed.x-1, seed.y) = label;
						p.push_back(Point2d(seed.x-1, seed.y));
						++area;
						if (row_min > seed.x - 1)
						{
							row_min = seed.x - 1;
						}
					}
					seed = p.at(p.size() - 1);//
					p.pop_back();//删除最后一个元素
				}
				label_area[label] = area;//将联通域的面积保存起来
				//Rect l = Rect( row_min,col_min,(row_max-row_min),(col_max-col_min ));

				Rect l = Rect(col_min, row_min, (col_max - col_min), (row_max - row_min));
				rect[label] = l;			
			}
		}	
	}
	cout << "共有" << label << "个连通区域" << endl;
	auto s= label_area.begin();
	while (s != label_area.end())
	{
		cout << "第" << s->first << "个联通区域的面积=" << s->second << endl;
		++s;
	}
	color(im);
}
//对图像进行染色
void color(Mat imm)
{
	Mat image(imm.rows, imm.cols, CV_8UC3, Scalar(0,0, 0));
	for (int i = 0; i < imm.rows; i++)
		{
		for (int j = 0; j < imm.cols; j++)
		{
			int d = imm.at<uchar>(i, j);
			if (d != 0)
			{
				image.at<Vec3b>(i, j)[0] = dic[d].x;
				image.at<Vec3b>(i, j)[1] = dic[d].y;
				image.at<Vec3b>(i, j)[2] = dic[d].z;
			}		
		}
		}
	auto ss = rect.begin();
	while (ss != rect.end())
	{
		rectangle(image,ss->second ,Scalar(0,255,0),2);
		++ss;
	}
	imshow("2", image);
	waitKey(0);
}
void main()
{
	Mat im = imread("c:\\users\\x\\desktop\\test.jpg");
	Mat dst, gray;
	cvtColor(im, gray, COLOR_BGR2GRAY);
	threshold(gray, dst, 50, 255, THRESH_BINARY);
	seedfill(dst);
}

Python实现

""" 
Author Zjh
2019/1/5
by-Xaut
"""
import cv2
import numpy as np
import matplotlib.pyplot as plt
l=[]
dic={}
rect={}
label=0
""" 种子填充法进行填充 """
def fill(im):
    global label
    row,col=im.shape[:2]
    for i in range(row):
        for j in range(col):
            if im[i,j]==255:
                l.append([i,j])
                seed=(i,j)
                label=label+1
                row_min=i
                row_max=i
                col_min=j
                col_max=j
                dic[label]=np.random.randint(0,255,(1,3))#产生随机的颜色,对不同的连通区域进行标记
                im[i,j]=label #标记
                while(len(l)!=0):
                    """遍历四个邻域"""
                    if im[seed[0],seed[1]+1]==255:
                        im[seed[0],seed[1]+1]=label
                        l.append([seed[0],seed[1]+1])
                        if col_max<seed[1]+1:
                            col_max=seed[1]+1
                    if im[seed[0]+1,seed[1]]==255:
                        im[seed[0]+1,seed[1]]=label
                        l.append([seed[0]+1,seed[1]])
                        if row_max<seed[0]+1:
                            row_max=seed[0]+1
                    if im[seed[0],seed[1]-1]==255:
                        im[seed[0],seed[1]-1]=label
                        l.append([seed[0],seed[1]-1])
                        if col_min>seed[1]-1:
                            col_min=seed[1]-1
                    if im[seed[0]-1,seed[1]]==255:
                        im[seed[0]-1,seed[1]]=label
                        l.append([seed[0]-1,seed[1]])
                        if row_min>seed[0]-1:
                            row_min=seed[0]-1
                    seed=l[-1]
                    l.pop()#相当于堆栈出栈的过程
                rect[label]=[col_min,row_min,col_max,row_max]
    color(im)
""" 绘制矩形框 """
def color(img):
    row,col=img.shape
    out=np.zeros((row,col,3),np.uint8)
    for i in range(row):
        for j in range(col):
            d=img[i,j]
            if d!=0:
                out[i,j]=dic[d]
    for x in rect.keys():
        cv2.rectangle(out,(rect[x][0],rect[x][1]),(rect[x][2],rect[x][3]),(0,255,0),2)
    cv2.imshow("Annie",out)
    cv2.waitKey(0)
img=cv2.imread("c:\\users\\x\\desktop\\god.png",0)
im=cv2.threshold(img,50,255,cv2.THRESH_BINARY)[1]
fill(im)

小结:种子填充法主要还是堆栈出栈的一个过程。通过这个小例子发现语言其实无关紧要,算法逻辑才是核心,以后还是要多学习别人程序里优秀的思想,这样才能进步的更快 ——2019/1/5 于学科二楼!

猜你喜欢

转载自blog.csdn.net/zzzzjh/article/details/85868706
今日推荐