从图像中删除具有像素值总和<阈值的连接组件

问题描述 投票:2回答:2

简单来说,这是可用输入和我想要的相应输出的示例:

In: [ 0 0 0 0 0 0 1 0 1 0
      0 6 6 0 0 0 0 1 1 0
      0 8 9 0 0 0 0 0 1 1
      8 0 0 0 9 9 0 0 0 0
      0 0 0 0 8 8 0 0 0 0
      0 0 0 0 0 0 0 0 0 0
      9 9 7 0 0 0 0 0 1 0
      0 6 8 0 0 0 0 3 2 0
      0 0 0 0 0 0 0 2 1 0
      0 0 0 0 0 0 0 0 0 0 ]

使用cv2.connectedComponents()进行二值化并获取标记图像后:

labels: [ 0 0 0 0 0 0 1 0 1 0
          0 2 2 0 0 0 0 1 1 0
          0 2 2 0 0 0 0 0 1 1
          2 0 0 0 3 3 0 0 0 0
          0 0 0 0 3 3 0 0 0 0
          0 0 0 0 0 0 0 0 0 0
          4 4 4 0 0 0 0 0 5 0
          0 4 4 0 0 0 0 5 5 0
          0 0 0 0 0 0 0 5 5 0
          0 0 0 0 0 0 0 0 0 0 ]

从这里,我想要以下输出:

Out: [0 0 0 0 0 0 0 0 0 0
      0 6 6 0 0 0 0 0 0 0
      0 8 9 0 0 0 0 0 0 0
      8 0 0 0 9 9 0 0 0 0
      0 0 0 0 8 8 0 0 0 0
      0 0 0 0 0 0 0 0 0 0
      9 9 7 0 0 0 0 0 0 0
      0 6 8 0 0 0 0 0 0 0
      0 0 0 0 0 0 0 0 0 0
      0 0 0 0 0 0 0 0 0 0 ]

存在许多连接组件(在这种情况下:8个连接的5个组件)。在Out中去除其像素之和<10(阈值)的分量(In)。

如何在C ++中实现它(可能使用OpenCV)?

我已经使用OpenCV在Python上完成了它,但是无法在C ++上实现。

这是我的Python代码的一部分,如果有用(标签是cv2.connectedComponents()的输出):

for cnt in range(1, labels.max()+1): 
        idx = np.where(labels.copy() == cnt)
        valMat = In[idx]
        sum_valMat = sum(valMat)
        if sum_valMat > 3000:
            fingerNodes[idx] = 0

输入是一个简单的2D矩阵。这是连接组件的示例:

enter image description here

c++ opencv image-processing opencv3.0
2个回答
2
投票

您已经在Python中实现了这一点,因此您知道如何解决问题。我想能够在C ++中实现它是一个知道你想要使用的库的问题。

您的Python实现效率非常低:您遍历标签,并为每个标签访问每个图像像素(idx = np.where(labels.copy() == cnt))。如果您拥有多个标签,这可能会变得非常昂贵。

在下面的代码中,我循环一次图像以累积每个标签的图像强度之和,然后一次用计算的总和绘制图像(对于带有标签的每个像素,查找该标签的总和),然后再一次阈值这个图像。然后,我将此阈值图像用作遮罩,将输入图像中的像素设置为0,这是您不想保留的。

我在这里使用DIPlib。虽然我确信你可以用某种方式使用OpenCV来复制它,如果你真的想要使用它。

#include "diplib.h"
#include "dipviewer.h"
#include "diplib/file_io.h"
#include "diplib/regions.h"
#include "diplib/measurement.h"

int main() {
   // Create a test image with similar properties to your example
   dip::Image input = -dip::ImageReadICS( "/Users/cris/newdip/examples/cermet.ics" );
   input.At( input < 120 ) = 0;
   // Display
   dip::viewer::ShowSimple( input, "input image" );
   // Threshold and label
   dip::Image label = dip::Label( input > 0 );
   // Obtain sum of pixels per label
   dip::MeasurementTool measurementTool;
   auto msr = measurementTool.Measure( label, input, { "Mass" } );
   // Paint each label with the measured value
   dip::Image feature = dip::ObjectToMeasurement( label, msr[ "Mass" ] );
   // Create output as a copy of the input, with low feature values set to 0
   dip::Image output = input.Copy();
   output.At( feature < 100000 ) = 0;
   // Display
   dip::viewer::ShowSimple( output, "output image" );
   dip::viewer::Spin();
}

enter image description here


0
投票

如果你想坚持使用opencv,你可以使用cv::calcHist来计算每个标签的出现次数,以及对应于小于10的bin值的filrerout值。然后应该对得到的标签图像进行二值化,并按元素乘以来源是为了得到你想要的结果。

© www.soinside.com 2019 - 2024. All rights reserved.