C++ 如何识别二元图中的线连通孔
我从这个问题的投票结果最高的作者的答案中选择了一段代码: 将其重新格式化为:C++ 如何识别二元图中的线连通孔,c++,opencv,graphics,computer-vision,binary-image,C++,Opencv,Graphics,Computer Vision,Binary Image,我从这个问题的投票结果最高的作者的答案中选择了一段代码: 将其重新格式化为: cv::Mat image = cv::imread("image.jpg", 0); cv::Mat image_thresh; cv::threshold(image, image_thresh, 125, 255, cv::THRESH_BINARY); // Loop through the border pixels and if they're black, floodFill from there
cv::Mat image = cv::imread("image.jpg", 0);
cv::Mat image_thresh;
cv::threshold(image, image_thresh, 125, 255, cv::THRESH_BINARY);
// Loop through the border pixels and if they're black, floodFill from there
cv::Mat mask;
image_thresh.copyTo(mask);
for (int i = 0; i < mask.cols; i++) {
if (mask.at<char>(0, i) == 0) {
cv::floodFill(mask, cv::Point(i, 0), 255, 0, 10, 10);
}
if (mask.at<char>(mask.rows-1, i) == 0) {
cv::floodFill(mask, cv::Point(i, mask.rows-1), 255, 0, 10, 10);
}
}
for (int i = 0; i < mask.rows; i++) {
if (mask.at<char>(i, 0) == 0) {
cv::floodFill(mask, cv::Point(0, i), 255, 0, 10, 10);
}
if (mask.at<char>(i, mask.cols-1) == 0) {
cv::floodFill(mask, cv::Point(mask.cols-1, i), 255, 0, 10, 10);
}
}
// Compare mask with original.
cv::Mat newImage;
image.copyTo(newImage);
for (int row = 0; row < mask.rows; ++row) {
for (int col = 0; col < mask.cols; ++col) {
if (mask.at<char>(row, col) == 0) {
newImage.at<char>(row, col) = 255;
}
}
}
cv::imshow("filled image", mask);
cv::imshow("Final image", newImage);
cv::imwrite("final.jpg", newImage);
cv::waitKey(0);
return 0;
cv::Mat image=cv::imread(“image.jpg”,0);
cv::Mat图像_阈值;
cv::threshold(图像,图像阈值,125,255,cv::阈值二进制);
//循环通过边界像素,如果它们是黑色的,则从那里进行泛光填充
cv::Mat面罩;
图像_thresh.copyTo(掩码);
对于(int i=0;i
我知道它使用了泛光填充算法来填充孔洞,我已经在另一个示例图像上进行了测试:
通过检测所有9个孔,它的效果非常好
然而,我尝试了另一个略显复杂的图像:
这一次它将不起作用,它将用白色填充整个图形,并且它检测到的孔数是1700
我想我可能在这里缺乏一点重要的形态学知识,但我想也许我应该先对失败的图像进行“隐藏”,然后再将其插入作者的代码中
专家们能和我分享一些想法吗?因为我在谷歌上找不到类似的孔检测图。那么,当两个孔在二值图像中以白色路径连接时,孔的特殊之处是什么呢?请提前感谢 您的图像中有一个问题,它在图像的三个面周围有一个薄的白色条。该条还连接到左侧的4个白色矩形,这创建了一个额外的封闭轮廓/标高,我猜这会混淆“泛光填充” 我个人不喜欢使用“洪水填充”方法来解决在等高线内寻找孔洞的问题。我更喜欢将“findcontour”方法与“hierarchy”选项一起使用。请看一看。乍一看,它可能看起来有点复杂,但它提供了我们需要的所有信息 要查找的孔具有两个特性:
auto image = cv::imread(in_img_path, cv::ImreadModes::IMREAD_GRAYSCALE);
cv::threshold(image, image, 128, 255, cv::THRESH_OTSU);
std::vector<std::vector<cv::Point>> contours, selected_contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(image, contours, hierarchy, cv::RetrievalModes::RETR_TREE, cv::ContourApproximationModes::CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); i++) {
if (hierarchy[i][2] == -1 && hierarchy[i][3] != -1) //the contour has no children but has a parent
selected_contours.emplace_back(std::move(contours[i]));
}
cv::Mat drawing_image(image.size(), image.type(), cv::Scalar::all(0));
for (int i = 0; i < selected_contours.size(); i++) {
cv::drawContours(drawing_image, selected_contours, i, cv::Scalar(255), 1);
}
孔的数量(选定的_轮廓的大小)为:71
“绘图图像”将如下所示:
另一种简单的方法是使用轮廓区域过滤。其思想是,然后使用最小阈值区域执行轮廓区域过滤。如果轮廓通过此阈值过滤器,则我们将其视为有效轮廓。以下是带有
500
阈值的结果。您可能需要根据您的图像进行更改
我用Python实现了它,但是您可以很容易地将相同的方法应用到C中++
import cv2
import numpy as np
# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.png')
mask = np.zeros(image.shape[:2], 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_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area < 500:
cv2.drawContours(image,[c],0,(36,255,12),-1)
cv2.drawContours(mask,[c],0,255,1)
cv2.imshow('mask', mask)
cv2.imshow('image', image)
cv2.waitKey()
导入cv2
将numpy作为np导入
#加载图像、灰度、大津阈值
image=cv2.imread('1.png')
掩码=np.zero(image.shape[:2],dtype=np.uint8)
灰色=cv2.CVT颜色(图像,cv2.COLOR\u BGR2GRAY)
thresh=cv2.阈值(灰色,0,255,cv2.thresh\u二进制\u INV+cv2.thresh\u OTSU)[1]
#查找轮廓并使用轮廓区域进行过滤
cnts=cv2.查找对象(阈值、cv2.RETR\u树、cv2.链近似值、简单值)
如果len(cnts)==2个其他cnts[1],则cnts=cnts[0]
对于碳纳米管中的碳:
面积=cv2。轮廓面积(c)
如果面积小于500:
cv2.等高线图(图[c],0,(36255,12),-1)
cv2.绘制轮廓(掩模[c],0255,1)
cv2.imshow(“面具”,面具)
cv2.imshow(“图像”,图像)
cv2.waitKey()
这非常有用。非常好,谢谢你的提示和修改过的算法!
import cv2
import numpy as np
# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.png')
mask = np.zeros(image.shape[:2], 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_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area < 500:
cv2.drawContours(image,[c],0,(36,255,12),-1)
cv2.drawContours(mask,[c],0,255,1)
cv2.imshow('mask', mask)
cv2.imshow('image', image)
cv2.waitKey()