简单来说,这是一个可用输入和我想要的相应输出的例子:
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个组件)。 In 的组件,其像素总和<在 Out 中删除10(阈值)。
如何在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矩阵。这是连接组件的示例:
答案 0 :(得分: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();
}
答案 1 :(得分:0)
如果您想坚持使用opencv,可以使用cv::calcHist
来计算每个标签的出现次数,以及对应于小于10的bin值的filrerout值。
然后应将生成的标签图像进行二值化,并按元素乘以源,以获得所需的结果。