zoukankan      html  css  js  c++  java
  • CV学习日志:CV开发之寻找连通域

             OpenCV中为人熟知的提取连通域的函数是connectedComponents,但它是针对灰度图像的。其实,OpenCV中还有一个函数可以提取short或ushort图像的连通域且对其源码稍加修改就可以提取任何类型的矩阵的连通域,此函数就是filterSpeckles。它原本是用于后处理StereoBM和StereoSGBM生成的视差图,但我们完全可以对扩展其应用,用于提取任何类型矩阵的连通域。

             filterSpeckles的关键函数有三个:newVal、maxSpeckleSize、maxDiff。

             (1)maxDiff:相邻元素的值小于此值,认为是属于同一连通域

             (2)maxSpeckleSize:连通域的像素个数小于此值,则被滤掉。

             (3)newVal:被滤掉的连通域设置为此值。

             OpenCV中寻找连通域使用的是深度搜索法DFS。这里,我提取其源码并增加了基于广度搜索法BFS的实现。通过对DFS和BFS,DFS效率更高,符合连通域提取原理。

     

             以下是详细代码,依赖于C++14、OpenCV4.x和Spdlog。

      1 #include <opencv2/opencv.hpp>
      2 #include <spdlog/spdlog.h>
      3 using namespace std;
      4 using namespace cv;
      5 #define RANDOM(min, max) (rand() % ((max) - (min) + 1) + (min))
      6 #define ns1970 chrono::time_point_cast<chrono::nanoseconds>(chrono::system_clock::now()).time_since_epoch().count()
      7 class FilterSpeckles
      8 {
      9 public:
     10     static void TestMe(int argc = 0, char** argv = 0)
     11     {
     12         int N = 999;
     13         for (int k = 0; k < N; ++k)
     14         {
     15             //1.GenerateData
     16             int rows = RANDOM(128, 1024);
     17             int cols = RANDOM(128, 1024);
     18             Mat_<uchar> src8u(rows, cols); randu(src8u, 0, UINT8_MAX);
     19             Mat_<short> src16s(rows, cols); randu(src16s, 0, INT16_MAX);
     20             int invalidV = -1;
     21             int speckleSize = RANDOM(128, 1024);
     22             int speckleRange = RANDOM(2, 128);
     23 
     24             //2.CalcByOpenCV
     25             Mat_<uchar> src8u0 = src8u.clone();
     26             Mat_<short> src16s0 = src16s.clone();
     27             int64 t00 = ns1970; cv::filterSpeckles(src8u0, invalidV, speckleSize, speckleRange); t00 = ns1970 - t00;
     28             int64 t01 = ns1970; cv::filterSpeckles(src16s0, invalidV, speckleSize, speckleRange); t01 = ns1970 - t01;
     29 
     30             //3.CalcByBFS
     31             Mat_<uchar> src8u1 = src8u.clone();
     32             Mat_<short> src16s1 = src16s.clone();
     33             FilterSpeckles filter10(src8u1.rows, src8u1.cols, 3);
     34             FilterSpeckles filter11(src16s1.rows, src16s1.cols, 3);
     35             int64 t10 = ns1970; filter10.BFS(src8u1.ptr<uchar>(), invalidV, speckleSize, speckleRange); t10 = ns1970 - t10;
     36             int64 t11 = ns1970; filter11.BFS(src16s1.ptr<short>(), invalidV, speckleSize, speckleRange); t11 = ns1970 - t11;
     37 
     38             //4.CalcByDFS
     39             Mat_<uchar> src8u2 = src8u.clone();
     40             Mat_<short> src16s2 = src16s.clone();
     41             FilterSpeckles filter20(src8u2.rows, src8u2.cols, 3);
     42             FilterSpeckles filter21(src16s2.rows, src16s2.cols, 3);
     43             int64 t20 = ns1970; filter20.DFS(src8u2.ptr<uchar>(), invalidV, speckleSize, speckleRange); t20 = ns1970 - t20;
     44             int64 t21 = ns1970; filter21.DFS(src16s2.ptr<short>(), invalidV, speckleSize, speckleRange); t21 = ns1970 - t21;
     45 
     46             //5.AnalyzeError
     47             double infSrc8u0Src8u1 = norm(src8u0, src8u1);
     48             double infSrc16s0Src16s1 = norm(src16s0, src16s1);
     49             double infSrc8u0Src8u2 = norm(src8u0, src8u2);
     50             double infSrc16s0Src16s2 = norm(src16s0, src16s2);
     51             double sumFilters[4] = { 0, 0, 0, 0 };
     52             for (int i = 0; i < filter10.validAreas.size(); ++i)
     53                 for (int j = 0; j < filter10.validAreas[i].size(); ++j)
     54                     sumFilters[0] += std::abs(filter10.validAreas[i][j].x) + std::abs(filter10.validAreas[i][j].y) + std::abs(filter10.validAreas[i][j].z);
     55             for (int i = 0; i < filter11.validAreas.size(); ++i)
     56                 for (int j = 0; j < filter11.validAreas[i].size(); ++j)
     57                     sumFilters[1] += std::abs(filter11.validAreas[i][j].x) + std::abs(filter11.validAreas[i][j].y) + std::abs(filter11.validAreas[i][j].z);
     58             for (int i = 0; i < filter20.validAreas.size(); ++i)
     59                 for (int j = 0; j < filter20.validAreas[i].size(); ++j)
     60                     sumFilters[2] += std::abs(filter20.validAreas[i][j].x) + std::abs(filter20.validAreas[i][j].y) + std::abs(filter20.validAreas[i][j].z);
     61             for (int i = 0; i < filter21.validAreas.size(); ++i)
     62                 for (int j = 0; j < filter21.validAreas[i].size(); ++j)
     63                     sumFilters[3] += std::abs(filter21.validAreas[i][j].x) + std::abs(filter21.validAreas[i][j].y) + std::abs(filter21.validAreas[i][j].z);
     64             double infFilter10Filter20 = std::abs(sumFilters[0] - sumFilters[2]);
     65             double infFilter11Filter21 = std::abs(sumFilters[1] - sumFilters[3]);
     66 
     67             //6.PrintError
     68             spdlog::info("LoopCount: {}      timeVS: {} vs {}   {} vs {}", k, t10 - t00, t20 - t00, t11 - t01, t21 - t01);
     69             if (infSrc8u0Src8u1 > 0 || infSrc16s0Src16s1 > 0 || infSrc8u0Src8u2 > 0 || infSrc16s0Src16s2 > 0 || infFilter10Filter20 > 0 || infFilter11Filter21 > 0)
     70             {
     71                 spdlog::info("5.1PrintError");
     72                 spdlog::info("infSrc8u0Src8u1: {}", infSrc8u0Src8u1);
     73                 spdlog::info("infSrc16s0Src16s1: {}", infSrc16s0Src16s1);
     74                 spdlog::info("infSrc8u0Src8u2: {}", infSrc8u0Src8u2);
     75                 spdlog::info("infSrc16s0Src16s2: {}", infSrc16s0Src16s2);
     76                 spdlog::info("infFilter10Filter20: {}", infFilter10Filter20);
     77                 spdlog::info("infFilter11Filter21: {}", infFilter11Filter21);
     78                 spdlog::info("Press any key to continue");
     79                 getchar();
     80             }
     81         }
     82     }
     83 
     84 private://ImaSize
     85     int rows = 0;
     86     int cols = 0;
     87     int total = 0;
     88     int saveOption = 0; //0-none, 1-valid, 2-small, 3-both
     89 
     90 private://BufData
     91     int* labeldata = 0;
     92     bool* typedata = 0;
     93     Point3i* dfsdata = 0;
     94     vector<char> buffer = {};
     95 
     96 public://AreaData
     97     vector<Point3i> area = {};//Point2iForXY or intForPos
     98     vector<vector<Point3i>> validAreas = {};
     99     vector<vector<Point3i>> smallAreas = {};
    100 
    101 public:
    102     FilterSpeckles(int rows0, int cols0, int saveOption0)
    103     {
    104         //1.
    105         rows = rows0;
    106         cols = cols0;
    107         total = rows * cols;
    108         saveOption = saveOption0;
    109 
    110         //2.
    111         int bufSize = total * (sizeof(int) + sizeof(bool) + sizeof(Point3i));
    112         buffer.resize(bufSize);
    113         labeldata = (int*)buffer.data();
    114         typedata = (bool*)(labeldata + total);
    115         dfsdata = (Point3i*)(typedata + total);
    116 
    117         //3.
    118         area.reserve(total);
    119         if (saveOption == 1 || saveOption == 3) validAreas.reserve(total);
    120         if (saveOption == 2 || saveOption == 3) smallAreas.reserve(total);
    121     }
    122     template <typename dp> bool BFS(dp* imadata, int invalidV, int speckleSize, int speckleRange)
    123     {
    124         validAreas.clear(); smallAreas.clear();
    125         memset(labeldata, 0, total * sizeof(labeldata[0]));
    126         for (int i = 0, label = 0; i < rows; ++i)
    127         {
    128             dp* imadataI = imadata + i * cols;
    129             int* labeldataI = labeldata + i * cols;
    130 
    131             for (int j = 0; j < cols; ++j)
    132             {
    133                 //1.InvalidPoint
    134                 if (imadataI[j] == invalidV) continue;
    135 
    136                 //2.LabeledPoint
    137                 if (labeldataI[j])
    138                 {
    139                     if (typedata[labeldataI[j]])
    140                         imadataI[j] = (dp)invalidV;
    141                     continue;
    142                 }
    143 
    144                 //3.UnlabeledPoint
    145                 labeldataI[j] = ++label;
    146                 area.clear(); area.push_back(Point3i(j, i, i * cols + j));
    147                 for (int k = 0, ii, jj, cur; k < area.size(); ++k)
    148                 {
    149                     ii = area[k].y;
    150                     jj = area[k].x;
    151                     cur = area[k].z;
    152                     dp* imadataX = imadata + cur;
    153                     int* labeldataX = labeldata + cur;
    154 
    155                     if (ii < rows - 1 && !labeldataX[+cols] && imadataX[+cols] != invalidV && abs(imadataX[0] - imadataX[+cols]) <= speckleRange)
    156                     {
    157                         labeldataX[+cols] = label;
    158                         area.push_back(Point3i(jj, ii + 1, (ii + 1) * cols + jj));
    159                     }
    160 
    161                     if (ii > 0 && !labeldataX[-cols] && imadataX[-cols] != invalidV && abs(imadataX[0] - imadataX[-cols]) <= speckleRange)
    162                     {
    163                         labeldataX[-cols] = label;
    164                         area.push_back(Point3i(jj, ii - 1, (ii - 1) * cols + jj));
    165                     }
    166 
    167                     if (jj < cols - 1 && !labeldataX[+1] && imadataX[+1] != invalidV && abs(imadataX[0] - imadataX[+1]) <= speckleRange)
    168                     {
    169                         labeldataX[+1] = label;
    170                         area.push_back(Point3i(jj + 1, ii, ii * cols + jj + 1));
    171                     }
    172 
    173                     if (jj > 0 && !labeldataX[-1] && imadataX[-1] != invalidV && abs(imadataX[0] - imadataX[-1]) <= speckleRange)
    174                     {
    175                         labeldataX[-1] = label;
    176                         area.push_back(Point3i(jj - 1, ii, ii * cols + jj - 1));
    177                     }
    178                 }
    179 
    180                 //4.MarkLabel
    181                 if (area.size() <= speckleSize)
    182                 {
    183                     typedata[labeldataI[j]] = true;
    184                     imadataI[j] = (dp)invalidV;
    185                     if (saveOption == 2 || saveOption == 3) smallAreas.push_back(area);
    186                 }
    187                 else
    188                 {
    189                     typedata[labeldataI[j]] = false;
    190                     if (saveOption == 1 || saveOption == 3) validAreas.push_back(area);
    191                 }
    192             }
    193         }
    194         return true;
    195     }
    196     template <typename dp> bool DFS(dp* imadata, int invalidV, int speckleSize, int speckleRange)
    197     {
    198         validAreas.clear(); smallAreas.clear();
    199         memset(labeldata, 0, total * sizeof(labeldata[0]));
    200         for (int i = 0, label = 0; i < rows; ++i)
    201         {
    202             dp* imadataI = imadata + i * cols;
    203             int* labeldataI = labeldata + i * cols;
    204 
    205             for (int j = 0; j < cols; ++j)
    206             {
    207                 //1.InvalidPoint
    208                 if (imadataI[j] == invalidV) continue;
    209 
    210                 //2.LabeledPoint
    211                 if (labeldataI[j])
    212                 {
    213                     if (typedata[labeldataI[j]])
    214                         imadataI[j] = (dp)invalidV;
    215                     continue;
    216                 }
    217 
    218                 //3.UnlabeledPoint
    219                 labeldataI[j] = ++label;
    220                 dfsdata[0] = Point3i(j, i, i * cols + j);
    221                 area.clear(); area.push_back(dfsdata[0]);
    222                 for (int k = 0, ii, jj, cur; k >= 0; --k)
    223                 {
    224                     ii = dfsdata[k].y;
    225                     jj = dfsdata[k].x;
    226                     cur = dfsdata[k].z;
    227                     dp* imadataX = imadata + cur;
    228                     int* labeldataX = labeldata + cur;
    229 
    230                     if (ii < rows - 1 && !labeldataX[+cols] && imadataX[+cols] != invalidV && abs(imadataX[0] - imadataX[+cols]) <= speckleRange)
    231                     {
    232                         labeldataX[+cols] = label;
    233                         dfsdata[k] = Point3i(jj, ii + 1, (ii + 1) * cols + jj);
    234                         area.push_back(dfsdata[k++]);
    235                     }
    236 
    237                     if (ii > 0 && !labeldataX[-cols] && imadataX[-cols] != invalidV && abs(imadataX[0] - imadataX[-cols]) <= speckleRange)
    238                     {
    239                         labeldataX[-cols] = label;
    240                         dfsdata[k] = Point3i(jj, ii - 1, (ii - 1) * cols + jj);
    241                         area.push_back(dfsdata[k++]);
    242                     }
    243 
    244                     if (jj < cols - 1 && !labeldataX[+1] && imadataX[+1] != invalidV && abs(imadataX[0] - imadataX[+1]) <= speckleRange)
    245                     {
    246                         labeldataX[+1] = label;
    247                         dfsdata[k] = Point3i(jj + 1, ii, ii * cols + jj + 1);
    248                         area.push_back(dfsdata[k++]);
    249                     }
    250 
    251                     if (jj > 0 && !labeldataX[-1] && imadataX[-1] != invalidV && abs(imadataX[0] - imadataX[-1]) <= speckleRange)
    252                     {
    253                         labeldataX[-1] = label;
    254                         dfsdata[k] = Point3i(jj - 1, ii, ii * cols + jj - 1);
    255                         area.push_back(dfsdata[k++]);
    256                     }
    257                 }
    258 
    259                 //4.MarkLabel
    260                 if (area.size() <= speckleSize)
    261                 {
    262                     typedata[labeldataI[j]] = true;
    263                     imadataI[j] = (dp)invalidV;
    264                     if (saveOption == 2 || saveOption == 3) smallAreas.push_back(area);
    265                 }
    266                 else
    267                 {
    268                     typedata[labeldataI[j]] = false;
    269                     if (saveOption == 1 || saveOption == 3) validAreas.push_back(area);
    270                 }
    271             }
    272         }
    273         return true;
    274     }
    275 };
    276 
    277 int main(int argc, char** argv) { FilterSpeckles::TestMe(argc, argv); return 0; }
    View Code
  • 相关阅读:
    前端响应式开发
    前端兼容性问题解决方案(二)
    web storage
    flex布局 滚动条失效
    ant-design-vue form表单 defaultValue默认值
    node express 中间件 http-proxy-middleware 和 express-http-proxy 转发 搞定 post 超时
    Math.min & Math.max & apply
    Backbone源码分析-noConflict
    安卓下浏览器(包括微信)video 小窗口播放
    前端工作流
  • 原文地址:https://www.cnblogs.com/dzyBK/p/14100478.html
Copyright © 2011-2022 走看看