【问题标题】:Detect drops of water on a card and count the amount and its size OpenCV C++检测卡片上的水滴并计算数量及其大小 OpenCV C++
【发布时间】:2020-03-15 09:41:58
【问题描述】:

我正在尝试获取诸如水敏感卡上水滴所占面积之类的信息,我必须在其中提取面积、滴数,并确定最大水滴和最小水滴。

示例图片:

到目前为止,我所做的是检测潮湿区域,但我很难检测到水滴并测量它们的大小和数量。

按照下面的代码,

如果有人可以提供帮助,我将不胜感激!

src = cv::imread("/Users/gustavovisentini/Documents/Developer/Desktop/OpenCV-Teste3.3.1/binary_image.png");

cout << "Loading Image...\n\n";
cvtColor( src, src_gray, COLOR_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
Mat canny_output;
Canny( src_gray, canny_output, thresh, thresh*2 );

vector<vector<Point>> contours;
findContours( src_gray, contours, RETR_TREE, CHAIN_APPROX_SIMPLE );

vector<vector<Point> > contours_poly( contours.size() );
vector<Rect> boundRect( contours.size() );
vector<Point2f>centers( contours.size() );
vector<float>radius( contours.size() );

for( size_t i = 0; i < contours.size(); i++ )
{
    approxPolyDP( contours[i], contours_poly[i], 3, true );
    boundRect[i] = boundingRect( contours_poly[i] );
    minEnclosingCircle( contours_poly[i], centers[i], radius[i] );
}

Mat drawing = src.clone();

for( size_t i = 0; i< contours.size(); i++ )
{
    Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
    drawContours( drawing, contours_poly, (int)i, color );
    rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2 );
    circle( drawing, centers[i], (int)radius[i], color, 2 );

}
stringstream temp;
temp << "Total: " << contours.size() << " - " << thresh << " - " << contours[1][1];
cv::putText(drawing, temp.str(), cv::Point(10,40), FONT_HERSHEY_PLAIN, 0.7, CV_RGB(255, 0, 0));

imshow( "Contours", drawing );

【问题讨论】:

  • 除非我们能重现这个问题,否则我们可能无能为力。这些类型的编码问题通常需要大量的设置和时间来理解确切的问题。

标签: c++ image opencv image-processing


【解决方案1】:

这是一种使用阈值处理 + 轮廓过滤的方法。使用这个截图输入图像:

我们先将图像转为灰度,然后通过 Otsu 的阈值得到二值图像

接下来我们在二值图像上找到轮廓,遍历每个轮廓,并使用轮廓区域进行过滤。为了确定水滴的总面积,我们保留一个total_area 变量并对每个轮廓的面积求和。液滴数是口罩上轮廓数的长度。为了确定最小或最大的下降,我们只需根据上升的轮廓区域对轮廓进行排序。第一个轮廓将是最小的下降,最后一个轮廓将是最大的下降。

这是检测到的液滴、滴数和总面积

Drops: 257
Total area: 31448.0

我在 Python 中实现了这种方法,但您可以轻松地将其转换为 C++

import cv2
import numpy as np

# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.png')
mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray,0,255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Find contours and filter using contour area
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

total_area = 0
drops = len(cnts)
smallest = sorted(cnts, key=cv2.contourArea)[0]
largest = sorted(cnts, key=cv2.contourArea)[-1]
for c in cnts:
    area = cv2.contourArea(c)
    total_area += area

# Draw largest and smallest drop onto a mask
cv2.drawContours(mask, [largest], -1, (255,255,255), -1)
cv2.drawContours(mask, [smallest], -1, (255,255,255), -1)

# Visualize result better
result = cv2.bitwise_and(image, image, mask=thresh)
result[thresh==0] = (255,255,255)

print('Drops: {}'.format(drops))
print('Total area: {}'.format(total_area))
cv2.imshow('thresh', thresh)
cv2.imshow('mask', mask)
cv2.imshow('result', result)
cv2.waitKey()

【讨论】:

  • 看不懂c++中这个掩码是怎么生成的(mask = np.zeros(image.shape, dtype=np.uint8))
  • 这个想法是创建一个与输入图像具有相同大小的空白黑色图像,其中每个像素都是 0。在 Python 中,图像使用 Numpy 数组表示,但我不确定等效的在 C++ 中是
【解决方案2】:

感谢您到目前为止的帮助!我遇到的另一个问题是如何找到没有圆形的水滴。通过这种方式,我可以分类什么是痛风,什么是卡排出的水。是否可以通过findContours知道这种格式?跟随具有这种不同水滴的图像。

【讨论】:

  • 另一个细节是液滴尺寸,因为卡片尺寸始终为 15cm x 7cm,我可以使用这些测量值来确定液滴尺寸吗?
猜你喜欢
  • 2018-08-30
  • 1970-01-01
  • 2015-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多