OpenCV二值图求最大连通区域算法(广度优先算法 BFS)

#include <iostream>
#include <opencv2\opencv.hpp>
#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <windows.h>
#include <math.h>
#include <queue>

using namespace std;using namespace cv;

#define WHITE 1
#define GRAY 2
#define BLACK 3
#define INFINITE 255

typedef CvPoint ElemType;

typedef struct
{
    bool vSign;//像素点是否被访问过的标记,ture已访问,false表示未访问,给图片添加的一个属性
    int pixelValue;//像素值
}isVisit;

typedef struct
{
    CvPoint regionPoint;//该连通区域起点的坐标
    int regionId;//第i个连通区域的标号
    int pointNum;//第i个连通区域的像素点的总个数
}connectRegionNumSet;

int calConnectRegionNumsBfs(IplImage *srcGray, vector<vector<isVisit>>& validPicture, vector<connectRegionNumSet> &regionSet);

int main() {
    IplImage * src = cvLoadImage("ff.jpg");
    IplImage * srcGray = NULL;

    if (src->nChannels == 1)
        goto next;
    srcGray = cvCreateImage(cvSize(src->width, src->height), 8, 1);
    cvCvtColor(src, srcGray, CV_RGB2GRAY);
    next:
    if (!srcGray)
        cvThreshold(src, srcGray, 66, 255, CV_THRESH_BINARY);
    else
        cvThreshold(srcGray, srcGray, 66, 255, CV_THRESH_BINARY);
    cvNamedWindow("srcBinaryGray");
    cvShowImage("srcBinaryGray", srcGray);
    vector<vector<isVisit> >validPoint;
    validPoint.resize(srcGray->height);
    for (int i = 0; i<validPoint.size(); i++)
        validPoint[i].resize(srcGray->width);
    vector<connectRegionNumSet>regionSet;//存放找到的各个连通区域 regionSet.size()为连通区域的个数。

    cout << "连通区域的数目:" << calConnectRegionNumsBfs(srcGray, validPoint, regionSet) << endl << endl;//计算连通区域数目

    char text[3];//设置连通区域的编号,最小标号为0,最大编号为99

    CvFont font;

    cvInitFont(&font, CV_FONT_HERSHEY_COMPLEX, 0.6, 0.6, 0, 1, 8);//设置字体//参数从左到右:字体初始化,字体格式,字体宽度,字体高度,字体倾斜度,字体粗细,字体笔画类型
    int max_pointNum = 0; //最大连通区域的像素点个数
    int max_regionId = 0;
    for (int i = 0; i<regionSet.size(); i++)
    {
        cout << "第" << i << "个连通区域的起点坐标 =(" << regionSet[i].regionPoint.x << "," << regionSet[i].regionPoint.y << ")" << ",像素总点数=" << regionSet[i].pointNum << endl;
        cout << "ID:"<<regionSet[i].regionId << endl;
        if (i < 10)
        {//连通区域的个数为个位数
            text[0] = ‘0‘;
            text[1] = ‘0‘ + i;
        }
        else
        {//连通区域的个数为十位数

            text[0] = ‘0‘ + (i) / 10;
            text[1] = ‘0‘ + (i) % 10;
        }
        text[2] = ‘\0‘;
        cvPutText(src, text, regionSet[i].regionPoint, &font, cvScalar(0, 0, 255));
        //找到最大连通区域,并标记----------------------------------------------
        if (max_pointNum < regionSet[i].pointNum)
        {
            max_regionId = i;
            max_pointNum = regionSet[i].pointNum;
        }
    }
    cout << "第" << max_regionId << "个连通区域最大" <<"像素总点数=" << regionSet[max_regionId].pointNum << endl;
    cvNamedWindow("src");
    cvShowImage("src", src);
    //cvShowImage("srcGray", srcGray);
    cvWaitKey(0);
    cvReleaseImage(&src);
    cvReleaseImage(&srcGray);
    cvDestroyAllWindows();
}

int calConnectRegionNumsBfs(IplImage *srcGray, vector<vector<isVisit>>& validPicture, vector<connectRegionNumSet> &regionSet)
{
    int regionId = 0;//管理连通区域标号的变量
    connectRegionNumSet regionSetTemp;//临时用到的regionSetTemp类型中间变量
    uchar * ptr = (uchar*)(srcGray->imageData);
    for (int y = 0; y < srcGray->height; y++)
    {//给图片加上一个是否已访问的属性
        ptr = (uchar*)(srcGray->imageData + y*srcGray->widthStep);
        for (int x = 0; x < srcGray->width; x++)
        {
            validPicture[y][x].pixelValue = (int)ptr[x];
            validPicture[y][x].vSign = false;//开始时默认都未访问
        }
    }
    queue<CvPoint> q;
    CvPoint foundValidPoint;
    for (int y = 0; y < srcGray->height; y++) {//给图片加上一个是否已访问的属性
        for (int x = 0; x < srcGray->width; x++) {
            if (validPicture[y][x].pixelValue && !validPicture[y][x].vSign) {//找到下一个连通区域的起点,即像素值非零且未被访问过的点
                int eachRegionAcc = 1;//表示即将要寻找的连通区域的总像素点个数;//将validPicture[y][x]点默认为即将生成的连通区域的起点
                regionSetTemp.regionPoint = cvPoint(x, y);//x表示列,y表示行
                regionSetTemp.regionId = regionId++;
                regionSetTemp.pointNum = 1;
                regionSet.push_back(regionSetTemp);//将该点设置为已访问,并对其执行入栈操作
                validPicture[y][x].vSign = true;
                q.push(cvPoint(x, y));
                while (!q.empty())
                {
                    foundValidPoint = q.front();
                    q.pop();
                    int i = foundValidPoint.x;//t
                    int j = foundValidPoint.y;//k
                    int minY = (j - 1 < 0 ? 0 : j - 1);
                    int maxY = ((j + 1 > srcGray->height - 1 ? srcGray->height - 1 : j + 1));
                    int minX = (i - 1 < 0 ? 0 : i - 1);
                    int maxX = (i + 1 > srcGray->width - 1 ? srcGray->width - 1 : i + 1);
                    for (int k = minY; k <= maxY; k++)
                    {//在八连通范围内(两点之间距离小于根号2的点),表示其相邻点,入栈c
                        for (int t = minX; t <= maxX; t++)
                        {
                            if (validPicture[k][t].pixelValue && !validPicture[k][t].vSign)//validPicture[k][t]如果没有访问过
                            {
                                validPicture[k][t].vSign = true;//标志为已访问,防止死循环
                                q.push(cvPoint(t, k));
                                eachRegionAcc++;//相邻点的数目加1                                                        
                            }
                        }
                    }
                }
                if (eachRegionAcc > 1) //要求:连通区域的点数至少要有两个
                    regionSet[regionSet.size() - 1].pointNum = eachRegionAcc;
                else
                {//单个像素点不算,如果单个像素点也算,去掉该else语句即可
                    regionSet.pop_back();//上述默认的即将生成的连通区域不符合要求,出栈
                    regionId--;
                }
            }
        }
    }
    return regionSet.size();
}

原文地址:https://www.cnblogs.com/jxLuTech/p/11072845.html

时间: 2024-08-10 16:55:43

OpenCV二值图求最大连通区域算法(广度优先算法 BFS)的相关文章

使用OpenCV查找二值图中最大连通区域

http://blog.csdn.net/shaoxiaohu1/article/details/40272875 使用OpenCV查找二值图中最大连通区域 标签: OpenCVfindCoutours 2014-10-19 22:31 2802人阅读 评论(0) 收藏 举报  分类: 图像与OpenCV(15)  版权声明:本文为shaoxiaohu原创文章,欢迎转载,请注明出处,谢谢. 上一篇博文中介绍了matlab查找最大连通区域的方法,OpenCV函数中也有类似的函数与之对应,findC

opencv二值图反色处理

反色处理指的是:如果原先图像的背景是白色,而目标是黑色的话:经过反色处理后,背景变为白色,目标变为黑色. 在opencv中,对于二值图的反色处理有两种方法: 之前处理好的二值图的定义为:Mat  binaryImg; 1.直接使用opencv中的函数: //! inverts each bit of array (dst = ~src) CV_EXPORTS_W void bitwise_not(InputArray src, OutputArray dst, InputArray mask=n

Kinect 2.0 + OpenCV 显示深度数据、骨架信息、手势状态和人物二值图

1.前言 Kinect 2.0实测比第一代性能提升非常多! 本来想简单地找个教程复制黏贴一下,居然还没有人写过C++版的Kinect 2.0教程,自己摸索了一下,现在把结果拿出来和大家分享. 实现的功能是:深度数据(Depth Data),骨架信息(Body Data),手势状态(Hand State)和人物二值图(就是图1的那个东西,微软官方称法是Body Index Data)的提取和显示. 效果如下: 图1 骨架信息,人物二值图和手势状态 图2 深度信息 2.安装 Kinect 2.0的安

用 Python 通过马尔可夫随机场(MRF)与 Ising Model 进行二值图降噪

前言 这个降噪的模型来自 Christopher M. Bishop 的 Pattern Recognition And Machine Learning (就是神书 PRML……),问题是如何对一个添加了一定椒盐噪声(Salt-and-pepper Noise)(假设噪声比例不超过 10%)的二值图(Binary Image)去噪. 原图 添加 10% 椒盐噪声的图 建模 下文中的数学表示: yi:噪声图中的像素 xi:原图中的像素,对应噪声图中的 yi 既然噪声图是从原图添加噪声而来,我们拥

zw&#183;准专利&#183;高保真二值图细部切分算法

zw·准专利·高保真二值图细部切分算法     高保真二值图细部切分算法,是中国字体协会项目的衍生作品.     说准专利算法,是因为对于图像算法的标准不了解,虽然报过专利,但不是这方面的,需要咨询专业的专利顾问.     原型是用opencv+python实现的,因为Halcon,对于协会的设计师,门槛太高,所以,特意设计了一套opencv+python的live-cd,解压即可,无需配置. 中国传统书法,有很多飞白.泼墨的手法,产生了很多小孔.孤点,从图像学角度,这些都是细小的感染区. 传统

S0.4 二值图与阈值化

目录 二值图的定义 二值图的应用 阈值化 二值化/阈值化方法 1,无脑简单判断 opencv3函数threshold()实现 2,Otsu算法(大律法或最大类间方差法) OpenCV3 纯代码实现大津法 OpenCV3 threshold算法调用Otsu阈值化 改进版本 OpenCV3函数adaptiveThreshold实现自适应阈值 二值图的定义 二值图是一种特殊的灰度图,即每个像素点要么是白(0),要么是黑(255) 无论是灰度图还是二值图都是用阈值化的知识. 二值图的应用 图像的二值化使

C语言实现将彩色BMP位图转化为二值图

CTF做了图片的隐写题,还没有形成系统的认识,先来总结一下BMP图的组成,并通过将彩色图转为二值图的例子加深下理解. 只写了位图二进制文件的格式和代码实现,至于诸如RGB色彩和调色板是什么的一些概念就不啰嗦了. BMP位图文件格式 BMP文件由文件头.位图信息头.调色板和图形数据四部分组成,真彩色图是没有调色板的.每部分的具体结构在代码中具体列出并解释. 结构体的对齐 定义文件头部各结构体时要注意对齐的问题,至于什么是结构体对齐,请看这篇博文,写的很详细http://www.cnblogs.co

opencv二值化处理

#include "stdafx.h"//对一张图片进行二值化处理 IplImage *pSrclmg =NULL;//载入的图片IplImage *pDeclmg =NULL;//生成的图像 void onTrackerSlid(int thresth){ /*int i,j,k; //设置一个阈值,如果大于这个阈值就赋为255,小于这个阈值就赋为0 int height =pDeclmg->height; int width =pDeclmg->width; int s

c语言实现灰度图转换为二值图

将上篇得到的灰度图转换为二值图,读取像素数据,低于某一值置0,否则设置为255,为得到更好的效果不同图片应采用不同的值 1 /* 2 2015年6月2日11:16:22 3 灰度图转换为二值图 4 blog:http://www.cnblogs.com/wd1001/ 5 */ 6 #include<stdio.h> 7 #include<malloc.h> 8 #include<stdlib.h> 9 /* 10 位图头结构 11 */ 12 #pragma pack