【问题标题】:Finding width and height of concave curved shaped blob找到凹弯曲形状斑点的宽度和高度
【发布时间】:2019-11-26 21:38:33
【问题描述】:

我一直在为计算这样一个图形的宽度和高度测量值的问题而摸不着头脑。主要挑战是我不能使用 miBoundingrectangle 并且无法从内部找出一种方法,无论哪种方式我都会丢失一些用于高度和宽度测量的像素。

示例输入:

样本输出:

是否有任何防故障方法来获得准确的尺寸测量?

下面是我试图找到内部边界最大矩形的解决方案。

_,contour2,_=cv2.findContours(im,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_NONE)
for c in contour2:
    area=cv2.contourArea(c)
    if area ==25224.0:
        print(area)
        n = np.squeeze(contour2[0])

        x = sorted(n, key=lambda a:a[0])
        left = x[0]
        right = x[-1]
        print("",left,right)
        y= sorted(n, key=lambda a:a[1])
        top = y[0]
        bottom = y[-1]
        cv2.drawContours(im,[c],-1,(128,128,128),2)
        cv2.circle(im, (left[0],left[1]), 4, (128,128,128), 8)
        cv2.circle(im, (right[0],right[1]), 4, (128,128,128), 8)
        cv2.circle(im, (top[0],top[1]), 4, (128,128,128), 8)
        cv2.circle(im, (bottom[0],bottom[1]), 4, (128,128,128), 8)

        roi_w = int(np.sqrt((top[0]-right[0])*(top[0]-right[0])(top[1]-right[1])*(top[1]-right[1])))
        roi_h = int(np.sqrt((top[0]-left[0])*(top[0]-left[0])+(top[1]-left[1])*(top[1]-left[1])))
                pts1 = np.float32([top,right,left])

        new_top = top
        new_right = [top[0] + roi_w, top[1]]
        new_left = [top[0], top[1] + roi_h]
        pts2 = np.float32([new_top,new_right,new_left])

     cv2.imshow("threshed", im)`

【问题讨论】:

  • 你能添加你的输入图像吗?
  • 对不起,进行了编辑:)
  • 您能否详细说明您想要在中心宽度或高度中获得的最小宽度和行数?
  • 在这种情况下是从质心(中心)开始的宽度和高度。

标签: python image opencv image-processing computer-vision


【解决方案1】:

这是一个 OpenCV 解决方案。主要思想是

  • 将图像转换为灰度和反转图像
  • 查找斑点的轮廓和质心
  • 使用 Numpy 切片抓取所有行/列像素
  • 计算非零像素以确定宽度/高度

我们将图像转换为灰度并反转它。这是我们将计算像素的图像,因为所需的 ROI 是白色的。从这里,我们使用cv2.moments() 找到斑点的轮廓和中心坐标。这为我们提供了 质心(即对象的中心 (x, y) 坐标)

M = cv2.moments(c)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])

接下来我们使用 Numpy 切片来获取所有的行和列像素。我们使用cv2.countNonZero() 像这样查找行/列的宽度/高度

row_pixels = cv2.countNonZero(gray[cY][:])
column_pixels = cv2.countNonZero(gray[:, cX])

这是一个可视化

这是结果

第 150 行

第 354 栏

import cv2
import numpy as np

image = cv2.imread('1.png')
inverted = 255 - image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = 255 - gray

cnts = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

for c in cnts:
    M = cv2.moments(c)
    cX = int(M["m10"] / M["m00"])
    cY = int(M["m01"] / M["m00"])

    cv2.circle(inverted, (cX, cY), 5, (36, 255, 12), -1)
    inverted[cY][:] = (36, 255, 12)
    inverted[:, cX] = (36, 255, 12)
    row_pixels = cv2.countNonZero(gray[cY][:])
    column_pixels = cv2.countNonZero(gray[:, cX])

print('row', row_pixels)
print('column', column_pixels)
cv2.imshow('inverted', inverted)
cv2.imwrite('inverted.png', image)
cv2.waitKey(0)

【讨论】:

  • 非常感谢您的帮助。非常感谢!
  • 不错的 OpenCV 解决方案,使用图像时刻获取质心,然后从那里计算行和列像素。非常干净和简单!它非常接近我的添加,但您使用质心而不是边界框的中心。
【解决方案2】:

这是一个 Imagemagick 解决方案。但是这个概念会给你一个线索,如何继续使用 OpenCV。这不是您想要的尺寸。但我能想到的最接近的方式。基本上,它是边界框内的最大值。也许 OpenCV 中也有类似的东西。

从外向内围绕图像的每个边缘进行迭代,直到每个剩余的边缘都是全黑的,没有白色(或相当接近)。

输入:

convert img.png -threshold 0 -define trim:percent-background=0% -trim +repage -format "%wx%h" +write info: result.png

returns: widthxheight => 144x317


补充:

这是另一个在 OpenCV 中应该很容易实现的解决方案。

修剪以获得最小外边界框。提取中间的行和列,它们的末端可能有一些白色。然后在四周涂上白色。然后再次修剪所有白色,这样你就剩下一个黑色的行和一列没有白色。然后得到单个黑色行和单个黑色列的尺寸。

width=`convert img.png -threshold 0 -trim +repage -gravity center -crop x1+0+0 +repage -bordercolor white -border 1x1 -trim +repage -format "%w" info:`
height=`convert img.png -threshold 0 -trim +repage -gravity center -crop 1x+0+0 +repage -bordercolor white -border 1x1 -trim +repage -format "%h" info:`
echo "width=$width; height=$height;"
returns: => width=145; height=352;

【讨论】:

  • @nathancy 谢谢。在修剪到最小外边界框后,使用中心行和列的尺寸查看我的附加解决方案。我想也可以取这两种方法的平均值。
  • 这似乎可行并且很有意义。谢谢 :)。我还在想opencv中是否有一些功能或特定的方法来解决这个问题。但感谢您清晰的解释。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-13
  • 2020-01-18
  • 2020-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多