【CCL】连通区域提取
生活随笔
收集整理的這篇文章主要介紹了
【CCL】连通区域提取
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
根據朋友給的一份原理寫的 感覺還挺清楚
#include "cv.h" #include "highgui.h" #include <stdio.h> using namespace cv;#define MAXWIDTH 352 #define MAXHEIGHT 288typedef 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
?
找到上面多字母問題的原因了。問題出在下面一句:
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 288typedef 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, "\n");//}//把森林中每一個顆樹都標成統一的顏色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】连通区域提取的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NOTIFYICONDATA结构
- 下一篇: java synchronized wa