Finding width and height of concave curved shaped blob

前端 未结 2 1192
星月不相逢
星月不相逢 2021-01-20 21:20

I have been scratching my head over this problem of calculating the width and height measurements of a figure like this. The major challenge is I cant use miBoundingrectangl

相关标签:
2条回答
  • 2021-01-20 21:35

    Here's an OpenCV solution. The main idea is

    • Convert image to grayscale and invert image
    • Find contour and centroid of the blob
    • Use Numpy slicing to grab all row/column pixels
    • Count non-zero pixels to determine width/height

    We convert the image to grayscale and invert it. This is the image we will count pixels on since the desired ROI is in white. From here, we find the contour of the blob and the center coordinates using cv2.moments(). This gives us the centroid (i.e., the center (x, y)-coordinates of the object)

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

    Next we use Numpy slicing to obtain all the row and column pixels. We use cv2.countNonZero() to find the width/height of the row/column like this

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

    Here's a visualization

    Here's the result

    row 150

    column 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)
    
    0 讨论(0)
  • 2021-01-20 21:46

    This is an Imagemagick solution. But the concept will give you a clue how to proceed with OpenCV. It is not quite the dimensions you want. But the closest way I could conceive. Basically, it is the maximum inside bounding box. Perhaps there is something similar in OpenCV.

    Iterate around each edge of the image from outside towards the inside until each remaining edge is fully black with no white (or reasonably close to that).

    Input:

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


    ADDITION:

    Here is another solution that should be easy to do in OpenCV.

    Trim to get the minimum outer bounding box. Extract the center row and column, which may have some white on the ends. Then pad with white all around. Then trim all the white again so you have one black row and column remaining with no white. Then get the dimensions of the single black row and single black column.

    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;
    
    0 讨论(0)
提交回复
热议问题