【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】连通区域提取的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 单片机小白学步系列(十六) 单片机/计算
- 下一篇: win7下如何解决对方可以ping通我,