【CCL】连通区域提取
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                【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, "
");
    //}
    //把森林中每一個顆樹都標成統一的顏色
    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
找到上面多字母問題的原因了。問題出在下面一句:
imgdst.at<uchar>(row, col) = nodenum;
這里nodenum是可能超過255的 但是在傳給imgdst時被強制轉換成了uchar型,導致后面的結果出錯。
用tmp.create(imgsrc.rows, imgsrc.cols, CV_32F);來修改錯誤。
修改后的代碼如下:
#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)
{
    Mat tmp;
    tmp.create(imgsrc.rows, imgsrc.cols, CV_32F);
    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的認為是背景 全黑色
            {
                tmp.at<int>(row, col) = 0;
            }
            else //前景
            {
                if(row != 0 && col != 0) //不是邊界
                {
                    if(imgsrc.at<uchar>(row, col) == imgsrc.at<uchar>(row, col - 1)) // 判斷 先左 后上 
                    {
                        tmp.at<int>(row, col) = tmp.at<int>(row, col - 1);  //如果和左邊相同 標號和左邊相同
                        if(imgsrc.at<uchar>(row, col) == imgsrc.at<uchar>(row - 1, col) && tmp.at<int>(row, col) != tmp.at<int>(row - 1, col)) //同時與左邊 上邊相連  且兩個序號不同
                        {
                            tmp.at<int>(row, col) = (tmp.at<int>(row, col) > tmp.at<int>(row - 1, col)) ? tmp.at<int>(row - 1, col) : tmp.at<int>(row, col);  //取小的編號
                            PTNode nodetmp1, nodetmp2;
                            nodetmp1 = nodes[tmp.at<int>(row, col - 1)];
                            nodetmp2 = nodes[tmp.at<int>(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)) //僅與上面相同 序號等于上面
                    {
                        tmp.at<int>(row, col) = tmp.at<int>(row - 1, col);    
                    }
                    else //與兩個方向的序號都不同 新建一個序號 序號與位置相同
                    {
                        nodenum++;  
                        tmp.at<int>(row, col) = nodenum;
                        nodes[tmp.at<int>(row, col)].parent = -1;
                        nodes[tmp.at<int>(row, col)].data = tmp.at<int>(row, col);
                    }
                }
                else if(row == 0 && col != 0) //橫向邊界
                {
                    if(imgsrc.at<uchar>(row, col) == imgsrc.at<uchar>(row, col - 1))
                    {
                        tmp.at<int>(row, col) = tmp.at<int>(row, col - 1);
                    }
                    else
                    {
                        nodenum++;
                        tmp.at<int>(row, col) = nodenum;   //這里有問題, nodenum可能會大于255 但是傳給tmp.at<int>(row, col) 時被轉換為uchar型 
                        nodes[tmp.at<int>(row, col)].parent = -1;
                        nodes[tmp.at<int>(row, col)].data = tmp.at<int>(row, col);
                    }
                }
                else if(col == 0 && row != 0) //豎向邊界
                {
                    if(imgsrc.at<uchar>(row, col) == imgsrc.at<uchar>(row - 1, col))
                    {
                        tmp.at<int>(row, col) = tmp.at<int>(row - 1, col);
                    }
                    else
                    {
                        nodenum++;
                        tmp.at<int>(row, col) = nodenum;
                        nodes[tmp.at<int>(row, col)].parent = -1;
                        nodes[tmp.at<int>(row, col)].data = tmp.at<int>(row, col);
                    }
                }
                else //開始的(0 ,0)點 直接新建
                {
                    nodenum++;
                    tmp.at<int>(row, col) = nodenum;
                    nodes[tmp.at<int>(row, col)].parent = -1;
                    nodes[tmp.at<int>(row, col)].data = tmp.at<int>(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 ", tmp.at<int>(row, col));
    //    }
    //    fprintf(out, "
");
    //}
    //把森林中每一個顆樹都標成統一的顏色
    for(row = 0; row < imgsrc.rows; row++)
    {
        for(col = 0; col < imgsrc.cols; col++)
        {
            PTNode nodetmp = nodes[tmp.at<int>(row, col)];  
            while(nodetmp.parent != -1)
            {
                nodetmp = nodes[nodetmp.parent];
            }
            imgdst.at<uchar>(row, col) = nodetmp.data * 51 % 255; //隨意設個顏色顯示
        }
    }
}
void main()
{
    IplImage* img = cvLoadImage("D:\Users\2.jpg", 0);
    IplImage* imgdst = cvCreateImage(cvGetSize(img), 8, 1);
    cvThreshold(img,img,125,255,0);
    cvNot(img, img);
    cvShowImage("ori", img);
    Mat src(img), dst(imgdst);
    GetCCL(src, dst);
    cvShowImage("ccl", imgdst);
    cvWaitKey(0);
}
修正后結果就好了。有幾個字母看起來像是丟了,其實是因為我隨機選顏色,可能導致用黑色填充。
總結
以上是生活随笔為你收集整理的【CCL】连通区域提取的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 单片机小白学步系列(十六) 单片机/计算
- 下一篇: 单片机小白学步系列(十七) 单片机/计算
