本文介绍了迭代自适应阈值和形状分析检测集群圆形物体的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在开发一个应用程序来计算圆形对象如图片细菌菌落。

I have been developing an application to count circular objects such as bacterial colonies from pictures.

什么可以很容易的事实是,对象是一般从井背景不同。

What make it easy is the fact that the objects are generally well distinct from the background.

然而,一些困难进行分析技巧:

However, few difficulties make the analysis tricky:

  1. 在后台将present逐步以及快速的强度变化。
  2. 在容器的边缘时,对象将是椭圆形而不是圆形。
  3. 的物体边缘有时相当模糊的。
  4. 的对象将集群。
  5. 的对象可以是非常小的(直径6px)
  6. 最终,该算法将被用来(通过GUI)通过不具有图像分析的深刻理解人的,所以参数必须直观和很少。

这个问题一直地址多次在科学文献和解决,例如,采用圆形Hough变换或流域的方法,但是我从来没有满意的结果。

The problem has been address many times in the scientific literature and "solved", for instance, using circular Hough transform or watershed approaches, but I have never been satisfied by the results.

这是描述一个简单的方法是让前台通过自适应阈值和拆分(正如我在this帖子)使用距离变换的群集对象。

One simple approach that was described is to get the foreground by adaptive thresholding and split (as I described in this post) the clustered objects using distance transform.

我已经成功地实现了这个方法,但它不能总是处理的强度突然变化。另外,我一直在问同行来与更新颖的方法。

I have successfully implemented this method, but it could not always deal with sudden change in intensity. Also, I have been asked by peers to come out with a more "novel" approach.

因此,我一直在寻找一种新的方法来提取前景。

因此​​,我调查了其他阈值/斑点检测方法。我想MSERs,但发现他们不是非常稳健,在我的情况很慢。

I therefore investigated other thresholding/blob detection methods.I tried MSERs but found out that they were not very robust and quite slow in my case.

我终于想出了一个算法,到目前为止,给我了优异的成绩:

I eventually came out with an algorithm that, so far, gives me excellent results:

  1. 我分裂了三个频道我的形象,降低其噪声(模糊/平均模糊)。对于每个通道:
  2. 在我申请手动实现自适应阈值的通过计算原有的渠道和卷积之间的绝对差值的第一步(由大内核模糊)之一。然后,对于阈值的所有相关的值:
  3. 在我申请的阈值对2的结果)
  4. 找到轮廓
  5. 在有效或无效的轮廓上授予它们的形状(大小,面积,凸...)
  6. 只有有效的连续区域(的通过等高线分隔),然后重新绘制在蓄压器(每通道1累加器)。
  7. 超过阈值累加连续区域之后,我最终与区域的分数的地图。该地区具有最高强度为那些完成了形态的筛选条件最频繁。
  8. 的三个地图(每个声道一个),然后被转换为灰色尺度和阈值(该阈值是由用户控制的)
  1. I split the three channels of my image and reduce their noise (blur/median blur). For each channel:
  2. I apply a manual implementation of the first step of adaptive thresholding by calculating the absolute difference between the original channel and a convolved (by a large kernel blur) one. Then, for all the relevant values of threshold:
  3. I apply a threshold on the result of 2)
  4. find contours
  5. validate or invalidate contours on the grant of their shape (size, area, convexity...)
  6. only the valid continuous regions (i.e. delimited by contours) are then redrawn in an accumulator (1 accumulator per channel).
  7. After accumulating continuous regions over values of threshold, I end-up with a map of "scores of regions". The regions with the highest intensity being those that fulfilled the the morphology filter criteria the most often.
  8. The three maps (one per channel) are then converted to grey-scale and thresholded (the threshold is controlled by the user)

只是向你展示一种形象我一起工作:这张照片重新的各部分的前3样本图像和我的算法的结果(蓝色=前景)presents在底部的部分。

Just to show you the kind of image I have to work with:This picture represents part of 3 sample images in the top and the result of my algorithm (blue = foreground) of the respective parts in the bottom.

下面是我的C ++实现:3-7

Here is my C++ implementation of : 3-7

/*
 * cv::Mat dst[3] is the result of the absolute difference between original and convolved channel.
 * MCF(std::vector<cv::Point>, int, int) is a filter function that returns an positive int only if the input contour is valid.
 */

/* Allocate 3 matrices (1 per channel)*/
cv::Mat accu[3];

/* We define the maximal threshold to be tried as half of the absolute maximal value in each channel*/
int maxBGR[3];
for(unsigned int i=0; i<3;i++){
    double min, max;
    cv::minMaxLoc(dst[i],&min,&max);
    maxBGR[i] = max/2;
    /* In addition, we fill accumulators by zeros*/
    accu[i]=cv::Mat(compos[0].rows,compos[0].cols,CV_8U,cv::Scalar(0));
}
/* This loops are intended to be multithreaded using
#pragma omp parallel for collapse(2) schedule(dynamic)
For each channel */
for(unsigned int i=0; i<3;i++){
    /* For each value of threshold (m_step can be > 1 in order to save time)*/
    for(int j=0;j<maxBGR[i] ;j += m_step ){
            /* Temporary matrix*/
            cv::Mat tmp;
            std::vector<std::vector<cv::Point> > contours;
            /* Thresholds dst by j*/
            cv::threshold(dst[i],tmp, j, 255, cv::THRESH_BINARY);
            /* Finds continous regions*/
            cv::findContours(tmp, contours, CV_RETR_LIST, CV_CHAIN_APPROX_TC89_L1);
            if(contours.size() > 0){
                /* Tests each contours*/
                for(unsigned int k=0;k<contours.size();k++){
                    int valid = MCF(contours[k],m_minRad,m_maxRad);
                    if(valid>0){
                        /* I found that redrawing was very much faster if the given contour was copied in a smaller container.
                         * I do not really understand why though. For instance,
                         cv::drawContours(miniTmp,contours,k,cv::Scalar(1),-1,8,cv::noArray(), INT_MAX, cv::Point(-rect.x,-rect.y));
                         is slower especially if contours is very long.
                         */
                        std::vector<std::vector<cv::Point> > tpv(1);
                        std::copy(contours.begin()+k, contours.begin()+k+1, tpv.begin());
                        /* We make a Roi here*/
                        cv::Rect rect = cv::boundingRect(tpv[0]);
                        cv::Mat miniTmp(rect.height,rect.width,CV_8U,cv::Scalar(0));
                        cv::drawContours(miniTmp,tpv,0,cv::Scalar(1),-1,8,cv::noArray(), INT_MAX, cv::Point(-rect.x,-rect.y));
                        accu[i](rect)    = miniTmp + accu[i](rect);
                    }
                }
            }
        }
    }
/* Make the global scoreMap*/
cv::merge(accu,3,scoreMap);
/* Conditional noise removal*/
if(m_minRad>2)
    cv::medianBlur(scoreMap,scoreMap,3);
cvtColor(scoreMap,scoreMap,CV_BGR2GRAY);

我有两个问题:

I have two questions:

  1. 什么是这样的前景提取方法的名称,你看不到任何理由,它可能是不正确的使用它在这种情况下?

  1. What is the name of such foreground extraction approach and do you see any reason for which it could be improper to use it in this case ?

由于递归地寻找和绘制的轮廓是相当密集的,我想提出我的算法更快。你可以指出我的任何方式来实现这一目标?

Since recursively finding and drawing contours is quite intensive, I would like to make my algorithm faster. Can you indicate me any way to achieve this goal ?

非常感谢您的帮助,

推荐答案

几年前,我写了检测细胞在显微镜图像的aplication。在code被写入在Matlab,我觉得现在是比较复杂的比它应该是(这是我的第一个CV项目),所以我只能概括的技巧,实际上是对你有帮助。顺便说一句,这是致命的慢,但它是真的很好的分离大集团双胞胎细胞。

Several years ago I wrote an aplication that detects cells in a microscope image. The code is written in Matlab, and I think now that is more complicated than it should be (it was my first CV project), so I will only outline tricks that will actually be helpful for you. Btw, it was deadly slow, but it was really good at separating large groups of twin cells.

予定义的度量通过该评估的机会,一个给定的点是一个小区的中心:  - 在它周围的圆形图案亮度降低  - 纹理亮度的变化遵循一个给定的模式  - 一个单元将不超过%相邻小区的覆盖更多

I defined a metric by which to evaluate the chance that a given point is the center of a cell: - Luminosity decreases in a circular pattern around it - The variance of the texture luminosity follows a given pattern - a cell will not cover more than % of a neighboring cell

有了它,我就开始反复地找到最好的细胞,将其标记为发现,然后寻找下一个。因为这样的搜索是昂贵的,我采用遗传算法,以更快的搜索我的特征空间。

With it, I started to iteratively find the best cell, mark it as found, then look for the next one. Because such a search is expensive, I employed genetic algorithms to search faster in my feature space.

一些结果如下:

这篇关于迭代自适应阈值和形状分析检测集群圆形物体的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 19:46