找出凹形弯曲斑点的宽度和高度

时间:2019-07-18 02:20:28

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

我一直在为计算这样一个图形的宽度和高度尺寸的问题而problem之以鼻。主要的挑战是我不能使用miBoundingrectangle,也找不到从内部进行边界的方法,无论哪种方式,我都会丢失一些用于高度和宽度测量的像素。

样本输入:

enter image description here

样本输出:

enter image description here

是否有任何防故障方法来进行精确的尺寸测量?

以下是我正在尝试找到内部边界最大矩形的解决方案。

_,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)`

2 个答案:

答案 0 :(得分:4)

这是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])

这是一个可视化

enter image description here

这是结果

  

第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)

答案 1 :(得分:2)

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

从外部到内部围绕图像的每个边缘进行迭代,直到每个剩余的边缘完全变成黑色,没有白色(或接近白色)。

输入:

enter image description here

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

returns: widthxheight => 144x317


enter image description here

添加:

这是在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;