图像连通域分析(Two-Pass & DFS )
来源:互联网 发布:网络流行语mgt什么意思 编辑:程序博客网 时间:2024/05/22 08:07
参考博客:http://blog.csdn.net/icvpr/article/details/10259577#reply
two-pass法原文中的代码有错误,添加了并查集数据结构后得以解决。
DFS方法无误。
本文代码的作用是,寻找图片中的所以连通域,并保留面积最大的连通域,其他区域删除。
#include <iostream> #include <opencv2\highgui\highgui.hpp> #include <opencv2\core\core.hpp> #include <opencv2\imgproc\imgproc.hpp> #include <map> #include <stack>#include <string> #include <list> #include <stdio.h>#include <time.h>using namespace std;using namespace cv; void myFillSeedFill(const Mat& _binImg, Mat& _labelImg) { if(_binImg.empty() || _binImg.type() != CV_8UC1) { return; } _labelImg.release(); _binImg.convertTo(_labelImg, CV_32SC1); int label = 1; int rows = _binImg.rows; int cols = _binImg.cols; vector<pair<int, int>> area; int maxLabel = 0; int maxLabelNum = 0; for(int i = 0; i < rows; ++i) { int * p = _labelImg.ptr<int>(i); for(int j = 0; j < cols; ++j) { if(p[j] == 1) { stack<pair<int, int>> s; s.push(pair<int, int>(i, j)); ++label; int curLabelNum = 0; while(!s.empty()) { pair<int, int> curPix = s.top(); int curX = curPix.first; int curY = curPix.second; int * curxptr = _labelImg.ptr<int>(curX); curxptr[curY] = label; //_labelImg.at<int>(curX, curY) = label; ++curLabelNum; s.pop(); if(curX-1 >= 0) { int * prexptr = _labelImg.ptr<int>(curX-1); if(prexptr[curY] == 1) { s.push(pair<int, int>(curX-1, curY)); } } if(curY-1 >= 0) { //int * prexptr = _labelImg.ptr<int>(curX-1); if(curxptr[curY-1] == 1) { s.push(pair<int, int>(curX, curY-1)); } } if(curX+1 < rows) { int * latexptr = _labelImg.ptr<int>(curX+1); if(latexptr[curY] == 1) { s.push(pair<int, int>(curX+1, curY)); } } if(curY+1 < cols) { //int * prexptr = _labelImg.ptr<int>(curX-1); if(curxptr[curY+1] == 1) { s.push(pair<int, int>(curX, curY+1)); } } } if(curLabelNum > maxLabelNum) { maxLabelNum = curLabelNum; maxLabel = label; } } } } for(int i = 0; i < rows; ++i) { int * p = _labelImg.ptr<int>(i); for(int j = 0; j < cols; ++j) { if(p[j] == maxLabel) { p[j] = 255; } else { p[j] = 0; } } } //总耗时: 0.5秒}int father[100000];vector<int> labelCnt(1000, 0);void make() { for(int i = 0; i < 100000; ++i) { father[i] = i; }}int Find_Set(int x) { if(x != father[x]) { father[x] = Find_Set(father[x]); } return father[x];}void Union(int x, int y) { int fx = Find_Set(x); int fy = Find_Set(y); if(fx == fy) { return; } father[fy] = fx;}void icvprCcaByTwoPass(const cv::Mat& _binImg, cv::Mat& _lableImg) { // connected component analysis (4-component) // use two-pass algorithm // 1. first pass: label each foreground pixel with a label // 2. second pass: visit each labeled pixel and merge neighbor labels // // foreground pixel: _binImg(x,y) = 1 // background pixel: _binImg(x,y) = 0 if (_binImg.empty() || _binImg.type() != CV_8UC1) { return ; } // 1. first pass _lableImg.release() ; _binImg.convertTo(_lableImg, CV_32SC1) ; int label = 1 ; // start by 2 std::vector<int> labelSet; labelSet.push_back(0) ; // background: 0 labelSet.push_back(1) ; // foreground: 1 int rows = _binImg.rows; int cols = _binImg.cols; int* data_firstRows = _lableImg.ptr<int>(0); if(data_firstRows[0] == 1) { data_firstRows[0] = ++label; labelSet.push_back(label); } for (int j = 1; j < cols; ++j) { //第一行初始化label if(data_firstRows[j] == 1) { if(data_firstRows[j-1] > 0) { data_firstRows[j] == data_firstRows[j-1]; } else { data_firstRows[j] = ++label; labelSet.push_back(label); } } } for(int j = 1; j < rows; ++j) { //第一列初始化label if(_lableImg.at<int>(j, 0) == 1) { if(_lableImg.at<int>(j-1, 0) > 0) { _lableImg.at<int>(j, 0) = _lableImg.at<int>(j-1, 0); } else { _lableImg.at<int>(j, 0) = ++label; labelSet.push_back(label); } } } //label = 1; make(); for (int i = 1; i < rows; i++) { int* data_preRow = _lableImg.ptr<int>(i-1) ; int* data_curRow = _lableImg.ptr<int>(i) ; for (int j = 1; j < cols; j++) { if (data_curRow[j] == 1) { std::vector<int> neighborLabels; neighborLabels.reserve(2); int leftPixel = data_curRow[j-1]; int upPixel = data_preRow[j]; if ( leftPixel > 1) { neighborLabels.push_back(leftPixel) ; } if (upPixel > 1) { neighborLabels.push_back(upPixel) ; } if (neighborLabels.empty()) { labelSet.push_back(++label) ; // assign to a new label data_curRow[j] = label ; labelSet[label] = label ; } else { std::sort(neighborLabels.begin(), neighborLabels.end()); int smallestLabel = neighborLabels[0]; data_curRow[j] = smallestLabel; for(size_t k = 1; k < neighborLabels.size(); k++) { int tmpLabel = neighborLabels[k]; Union(tmpLabel, smallestLabel); Union(smallestLabel, tmpLabel); } } } } } // 2. second pass for (int i = 0; i < rows; i++) { int* data = _lableImg.ptr<int>(i) ; for (int j = 0; j < cols; j++) { data[j] = Find_Set(data[j]); if(data[j] != 0) { labelCnt[data[j]]++; } } } vector<int>::iterator maxLabel = max_element(labelCnt.begin(), labelCnt.end()); cout << *maxLabel << endl; int maxL = distance(labelCnt.begin(), maxLabel); cout << maxL << endl; for (int i = 0; i < rows; i++) { int* data = _lableImg.ptr<int>(i) ; for (int j = 0; j < cols; j++) { if(data[j] == maxL) { data[j] = 255; } else { data[j] = 0; } } }}cv::Scalar icvprGetRandomColor() { uchar r = 255 * (rand()/(1.0 + RAND_MAX)); uchar g = 255 * (rand()/(1.0 + RAND_MAX)); uchar b = 255 * (rand()/(1.0 + RAND_MAX)); return cv::Scalar(b,g,r) ; } void icvprLabelColor(const cv::Mat& _labelImg, cv::Mat& _colorLabelImg) { if (_labelImg.empty() || _labelImg.type() != CV_32SC1) { return ; } std::map<int, cv::Scalar> colors ; int rows = _labelImg.rows ; int cols = _labelImg.cols ; _colorLabelImg.release() ; _colorLabelImg.create(rows, cols, CV_8UC3) ; _colorLabelImg = cv::Scalar::all(0) ; for (int i = 0; i < rows; i++) { const int* data_src = (int*)_labelImg.ptr<int>(i) ; uchar* data_dst = _colorLabelImg.ptr<uchar>(i) ; for (int j = 0; j < cols; j++) { int pixelValue = data_src[j] ; if (pixelValue > 1) { if (colors.count(pixelValue) <= 0) { colors[pixelValue] = icvprGetRandomColor() ; } cv::Scalar color = colors[pixelValue] ; *data_dst++ = color[0] ; *data_dst++ = color[1] ; *data_dst++ = color[2] ; } else { data_dst++ ; data_dst++ ; data_dst++ ; } } } } int main() { time_t t_start, t_end; /* Mat img, res; */ Mat binImage = imread("segmentationMask_bad.jpg",0); //将读入的彩色图像直接以灰度图像读入 //Mat binImage = imread("liantongyu.jpg",0); //小图,在递归调用中可用,图太大则只能使用TwoPass方法 //Mat binImage = imread("connect2.jpg",0); Mat showimg; showimg.release() ; binImage.convertTo(showimg, CV_8UC1) ; for(int i = 0; i < showimg.rows; ++i) { uchar * p = showimg.ptr<uchar>(i); for(int j = 0; j < showimg.cols; ++j) { if(p[j] > 50) p[j] = 225; else p[j] = 0; } } cv::imshow("showing", showimg); //cv::Mat binImage = cv::imread("../icvpr.com.jpg", 0) ; //cv::threshold(binImage, binImage, 50, 1, CV_THRESH_BINARY_INV) ; for(int i = 0; i < binImage.rows; ++i) { uchar * p = binImage.ptr<uchar>(i); for(int j = 0; j < binImage.cols; ++j) { if(p[j] > 50) p[j] = 1; else p[j] = 0; } } // connected component labeling cv::Mat labelImg ; t_start = clock(); //icvprCcaByTwoPass(binImage, labelImg) ; // cost 0.184s myFillSeedFill(binImage, labelImg); // cost 0.526s t_end = clock(); double duration = (double)(t_end - t_start) / CLOCKS_PER_SEC; cout << "cost " << duration << " s" << endl; // show result cv::Mat grayImg ; //labelImg *= 10 ; labelImg.convertTo(grayImg, CV_8UC1) ; cv::imshow("labelImg", grayImg) ; cv::Mat colorLabelImg ; icvprLabelColor(labelImg, colorLabelImg) ; cv::imshow("colorImg", colorLabelImg) ; cv::waitKey(0) ; return 0 ; }
阅读全文
0 0
- 图像连通域分析(Two-Pass & DFS )
- TWO-PASS连通域标记实现
- Two-pass连通域标记中的union-find结构
- 图像连通域分析
- 图像连通域分析
- 图像连通域分析
- 连通域染色,two-pass算法的并查集实现
- 连通区域快速标记的two-pass算法及其实现
- 图像中连通域分析算法处理
- OpenCV-二值图像连通域分析
- 图像分析:二值图像连通域标记
- 图像分析:二值图像连通域标记
- 图像分析:二值图像连通域标记
- CV1——二值图像分析之连通域
- 连通分量个数(dfs)
- Paintball(dfs判断连通)
- 图像分析:二值图像连通域标记-基于行程的标记方法
- 图像分析:二值图像连通域标记2-基于轮廓的标记
- 索引查找(分块查找)
- 3
- 第一周 枚举 例题4.称硬币 [POJ1013]
- 关于线索二叉树恢复成正常二叉树
- C#实现自动升级(附源码)
- 图像连通域分析(Two-Pass & DFS )
- codeforces 894C
- Aerospike的bin内存管理--即列内存管理
- Linux 静态库使用
- 123. Best Time to Buy and Sell Stock III
- char *s=“hello” 和 char s[]=“hello”的 区别
- 洛谷p1135 奇怪的电梯
- BZOJ3836: [Poi2014]Tourism
- 面试百度新浪头条b站阿里的研发实习生面试记录