【CCL】连通区域提取

根据朋友给的一份原理写的 感觉还挺清楚

#include "cv.h"
#include "highgui.h"
#include <stdio.h>
using namespace cv;

#define MAXWIDTH 352
#define MAXHEIGHT 288

typedef struct PTNode{
    int data;
    int parent;
}PTNode;

void GetCCL(Mat &imgsrc, Mat &imgdst)
{

    PTNode nodes[MAXWIDTH * MAXHEIGHT]; //线性树 数据的位置 与 数据本身 相同 即 nodes[x].data = x
    memset(nodes, 0, MAXWIDTH * MAXHEIGHT * sizeof(PTNode));
    int nodenum = 0;
    int row, col;
    nodes[0].data = 0;
    nodes[0].parent = -1;
    for(row = 0; row < imgsrc.rows; row++)
    {
        for(col = 0; col < imgsrc.cols; col++)
        {
            if(imgsrc.at<uchar>(row, col) == 0) //像素为0的认为是背景 全黑色
            {
                imgdst.at<uchar>(row, col) = 0;
            }
            else //前景
            {
                if(row != 0 && col != 0) //不是边界
                {
                    if(imgsrc.at<uchar>(row, col) == imgsrc.at<uchar>(row, col - 1)) // 判断 先左 后上
                    {
                        imgdst.at<uchar>(row, col) = imgdst.at<uchar>(row, col - 1);  //如果和左边相同 标号和左边相同
                        if(imgsrc.at<uchar>(row, col) == imgsrc.at<uchar>(row - 1, col) && imgdst.at<uchar>(row, col) != imgdst.at<uchar>(row - 1, col)) //同时与左边 上边相连  且两个序号不同
                        {
                            imgdst.at<uchar>(row, col) = (imgdst.at<uchar>(row, col) > imgdst.at<uchar>(row - 1, col)) ? imgdst.at<uchar>(row - 1, col) : imgdst.at<uchar>(row, col);  //取小的编号

                            PTNode nodetmp1, nodetmp2;
                            nodetmp1 = nodes[imgdst.at<uchar>(row, col - 1)];
                            nodetmp2 = nodes[imgdst.at<uchar>(row - 1, col)];
                            while(nodetmp1.parent != -1)
                            {
                                nodetmp1 = nodes[nodetmp1.parent];
                            }
                            while(nodetmp2.parent != -1)
                            {
                                nodetmp2 = nodes[nodetmp2.parent];
                            }
                            if(nodetmp2.data > nodetmp1.data)  //小的序号做parent 大序号做child
                            {
                                nodes[nodetmp2.data].parent = nodetmp1.data;  //这里一定要对nodes中的值修改, 直接写nodetmp2.parent = nodetmp1.data 是不行的因为nodetmp2只是一个局部变量 nodes[]里的值根本没有修改
                            }
                            else if(nodetmp2.data < nodetmp1.data)
                            {
                                nodes[nodetmp1.data].parent = nodetmp2.data;
                            }

                        }
                    }
                    else if(imgsrc.at<uchar>(row, col) == imgsrc.at<uchar>(row - 1, col)) //仅与上面相同 序号等于上面
                    {
                        imgdst.at<uchar>(row, col) = imgdst.at<uchar>(row - 1, col);
                    }
                    else //与两个方向的序号都不同 新建一个序号 序号与位置相同
                    {
                        nodenum++;
                        imgdst.at<uchar>(row, col) = nodenum;
                        nodes[imgdst.at<uchar>(row, col)].parent = -1;
                        nodes[imgdst.at<uchar>(row, col)].data = imgdst.at<uchar>(row, col);
                    }
                }
                else if(row == 0 && col != 0) //横向边界
                {
                    if(imgsrc.at<uchar>(row, col) == imgsrc.at<uchar>(row, col - 1))
                    {
                        imgdst.at<uchar>(row, col) = imgdst.at<uchar>(row, col - 1);
                    }
                    else
                    {
                        nodenum++;
                        imgdst.at<uchar>(row, col) = nodenum;
                        nodes[imgdst.at<uchar>(row, col)].parent = -1;
                        nodes[imgdst.at<uchar>(row, col)].data = imgdst.at<uchar>(row, col);
                    }
                }
                else if(col == 0 && row != 0) //竖向边界
                {
                    if(imgsrc.at<uchar>(row, col) == imgsrc.at<uchar>(row - 1, col))
                    {
                        imgdst.at<uchar>(row, col) = imgdst.at<uchar>(row - 1, col);
                    }
                    else
                    {
                        nodenum++;
                        imgdst.at<uchar>(row, col) = nodenum;
                        nodes[imgdst.at<uchar>(row, col)].parent = -1;
                        nodes[imgdst.at<uchar>(row, col)].data = imgdst.at<uchar>(row, col);
                    }
                }
                else //开始的(0 ,0)点 直接新建
                {
                    nodenum++;
                    imgdst.at<uchar>(row, col) = nodenum;
                    nodes[imgdst.at<uchar>(row, col)].parent = -1;
                    nodes[imgdst.at<uchar>(row, col)].data = imgdst.at<uchar>(row, col);
                }
            }

        }
    }

    //FILE * out = fopen("D:\\dst.txt", "w");
    //for(row = 0; row < imgsrc.rows; row++)
    //{
    //    for(col = 0; col < imgsrc.cols; col++)
    //    {
    //        fprintf(out, "%d ", imgdst.at<uchar>(row, col));
    //    }
    //    fprintf(out, "\n");
    //}
    //把森林中每一个颗树都标成统一的颜色
    for(row = 0; row < imgsrc.rows; row++)
    {
        for(col = 0; col < imgsrc.cols; col++)
        {
            PTNode nodetmp = nodes[imgdst.at<uchar>(row, col)];
            while(nodetmp.parent != -1)
            {
                nodetmp = nodes[nodetmp.parent];
            }
            imgdst.at<uchar>(row, col) = nodetmp.data * 52 % 255; //随意设个颜色显示
        }
    }

}

void main()
{
    IplImage* img = cvLoadImage("D:\\Users\\CCL\\1.jpg", 0);
    IplImage* imgdst = cvCreateImage(cvGetSize(img), 8, 1);
    cvThreshold(img,img,125,255,0);
    cvShowImage("ori", img);
    Mat src(img), dst(imgdst);
    GetCCL(src, dst);
    cvShowImage("ccl", imgdst);
    cvWaitKey(0);
}

效果:

但是下面的图片出了问题:

字母检测的很凌乱

但是单独把一个字母拿出来 放大再检测就ok

【CCL】连通区域提取

时间: 2024-08-24 05:52:34

【CCL】连通区域提取的相关文章

Opencv2系列学习笔记10(提取连通区域轮廓) 另一个

http://blog.csdn.net/lu597203933/article/details/17362457 连通区域指的是二值图像中相连像素组成的形状.而内.外轮廓的概念及opencv1中如何提取二值图像的轮廓见我的这篇博客:http://blog.csdn.net/lu597203933/article/details/14489225 轮廓的简单提取算法如下: 系统性地扫描图像直到遇到连通区域的一个点,以它为起始点,跟踪它的轮廓,标记边界上的像素.当轮廓完整闭合,扫描回到上一个位置,

利用颜色和形态学两种方法进行车牌区域提取的OpenCV代码

要想提取车牌号,首先你要定位车牌区域嘛,本文分别两种方法用,即颜色和形态学的方法,对车牌区域进行判定.说得是两种方法,其实两种方法并无多大的区别,只是有一步的判断标准不一样而已,你看了下面整理出的的思路就知道两者的区别真的很小了. 方法一:利用颜色提取车牌区域的思路: ①求得原图像的sobel边缘sobelMat ②在HSV空间内利用车牌颜色阈值对图像进行二值化处理,得到图像bw_blue→ ③由下面的判别标准得到图像bw_blue_edge for (int k = 1; k != heigh

OpenCV:二值图像连通区域分析与标记算法实现

编译环境: 操作系统:Win8.1  64位 IDE平台:Visual Studio 2013 Ultimate OpenCV:2.4.8 一.连通域 在图像中,最小的单位是像素,每个像素周围有8个邻接像素,常见的邻接关系有2种:4邻接与8邻接.4邻接一共4个点,即上下左右,如下左图所示.8邻接的点一共有8个,包括了对角线位置的点,如下右图所示.         如果像素点A与B邻接,我们称A与B连通,于是我们不加证明的有如下的结论: 如果A与B连通,B与C连通,则A与C连通. 在视觉上看来,彼

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

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

连通区域标记-行程扫描算法

1.连通域 对于一幅图像来说,它的基本组成单元是像素,每一个像素又对应一个灰度值. 联通区域标记针对的是二值图像,二值图像顾名思义就是它的灰度值只存在两种值---0或255的图像,一个连通区域指的是图像中那些位置相邻,灰度值相同的像素集合所组成的区域. 像素和像素之间的邻域关系有4邻域和8邻域,4邻域指的是当前像素的上下左右位置处的像素,8邻域是指上下左右和对角线位置处的像素. 如右图所示,分别对应的是像素的4邻域和8邻域位置关系   (x,y-1)   (x-1,y) (x,y) (x+1,y

连通区域

#include <iostream> #include <string> #include <list> #include <vector> #include <map> #include <stack> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> void icvprCcaByTwoPass(co

【连通区域个数】

#include <iostream> using namespace std; void DFS(int R,int W,int i, int j,int **visited,int **mVexs) { int r,w; visited[i][j] = 1; //将该位置的访问标签置为1 // 遍历该顶点的所有邻接顶点.若是没有访问过且元素为1,则继续深度访问 if(j>=1) { r = i;w = j-1; { if (!visited[r][w] && mVex

opencv 二值图像剔除小连通区域

二值图像剔除小面积连通区域在二值图像连通区域分析时很有用,之前做的使用采用了for循环的形式,后来学习了c++标准库,发现可以使用vector.erase(std::remove_if())的方法直接剔除.\ 统计二值图像的连通区域通过cv::findcontours()实现,二值图像轮廓的容器是std::vector.连通区域的面积可以由函数cv::contourArea()得到. 剔除小面积连通区域后,可以使用函数cv::drawContours()函数将轮廓画出,将其第三个参数设置为-1为

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;usin