检测图像中的多个矩形

Ark*_*koD 14 python opencv image-processing object-detection computer-vision

我试图检测这张图片中的管道数。为此,我使用 OpenCV 和基于 Python 的检测。基于对类似问题的现有答案,我能够提出以下步骤

  1. 打开图片
  2. 过滤它
  3. 应用边缘检测
  4. 使用轮廓
  5. 检查计数

在此处输入图片说明

当我们手动计数时,管道的总数约为 909给或取 4。

应用过滤器后

import cv2
import matplotlib.pyplot as plt
import numpy as np

img = cv2.imread('images/input-rectpipe-1.jpg')
blur_hor = cv2.filter2D(img[:, :, 0], cv2.CV_32F, kernel=np.ones((11,1,1), np.float32)/11.0, borderType=cv2.BORDER_CONSTANT)
blur_vert = cv2.filter2D(img[:, :, 0], cv2.CV_32F, kernel=np.ones((1,11,1), np.float32)/11.0, borderType=cv2.BORDER_CONSTANT)
mask = ((img[:,:,0]>blur_hor*1.2) | (img[:,:,0]>blur_vert*1.2)).astype(np.uint8)*255
Run Code Online (Sandbox Code Playgroud)

我得到这个蒙面图像

在此处输入图片说明

这在显示的可见矩形数量方面看起来相当准确。但是,当我尝试进行计数并在图片顶部绘制边界框时,它也会选择很多不需要的区域。对于圆,HoughCircles 有一种定义最大和最小半径的方法。矩形是否有类似的东西可以提高准确性。另外,我愿意接受有关解决此问题的替代方法的建议。

ret,thresh = cv2.threshold(mask,127,255,0)
contours,hierarchy = cv2.findContours(thresh, 1, 2)

count = 0

for i in range(len(contours)):

  count = count+1
  x,y,w,h = cv2.boundingRect(contours[i]) 
  rect = cv2.minAreaRect(contours[i])
  area = cv2.contourArea(contours[i])
  box = cv2.boxPoints(rect)
  ratio = w/h
  M = cv2.moments(contours[i])

  if M["m00"] == 0.0:
         cX = int(M["m10"] / 1 )
         cY = int(M["m01"] / 1 )

  if M["m00"] != 0.0:
    cX = int(M["m10"] / M["m00"])
    cY = int(M["m01"] / M["m00"])

  if (area > 50 and area < 220 and hierarchy[0][i][2] < 0 and (ratio > .5 and ratio < 2)):
    #cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
    cv2.circle(img, (cX, cY), 1, (255, 255, 255), -1)
    count = count + 1 



print(count)

cv2.imshow("m",mask)
cv2.imshow("f",img)
cv2.waitKey(0)
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

更新 基于第二个答案,我已将 c++ 代码转换为 python 代码并获得了更接近的结果,但仍然遗漏了一些明显的矩形。

在此处输入图片说明

MH3*_*304 7

当然,您可以按区域过滤它们。我拿了你的二进制图像并继续如下工作:

1- 对您从 findContours 中找到的所有轮廓进行循环

2- 在循环中检查每个轮廓是否是内部轮廓

3-从那些内部轮廓中,检查它们的面积,如果面积在可接受的范围内,检查每个轮廓的宽度/高度比,最后如果也很好,将该轮廓视为管道。

我对你的二进制图像做了上面的方法,发现了 794 个管道

在此处输入图片说明

(虽然有些框丢失了,您应该更改边缘检测器的参数以在图像中获得更多可分离的框。)

这是代码(它是c ++但很容易转换为python):

Mat img__1, img__2,img__ = imread("E:/R.jpg", 0);

threshold(img__, img__1, 128, 255, THRESH_BINARY);

vector<vector<Point>> contours;
vector< Vec4i > hierarchy;

findContours(img__1, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_NONE);

Mat tmp = Mat::zeros(img__1.size(), CV_8U);
int k = 0;
for (size_t i = 0; i < contours.size(); i++)
{
    double area = contourArea(contours[i]);
    Rect rec = boundingRect(contours[i]);
    float ratio = rec.width / float(rec.height);

    if (area > 50 && area < 220 && hierarchy[i][2]<0 && (ratio > .5 && ratio < 2) ) # hierarchy[i][2]<0 stands for internal contours
    {
        k++;
        drawContours(tmp, contours, i, Scalar(255, 255, 255), -1);
    }
}
cout << "k= " << k << "\n";
imshow("1", img__1); 
imshow("2", tmp);
waitKey(0);
Run Code Online (Sandbox Code Playgroud)