如何在图像中查找和测量弧长

时间:2016-03-13 09:24:08

标签: python opencv image-processing computer-vision

需要一些帮助。我需要获得从A点到B点的弧长,以厘米为单位,如图所示。此外,我们需要在唯一的腿上提取图像中可能没有的任何其他内容,或者可能不是。这是使用Python和OpenCV。我已经能够从他们中的许多人获得仅2个最大的轮廓,但努力保持只有最大的轮廓。下面给出的是当前代码。

# import the necessary packages
from __future__ import print_function
from skimage.feature import peak_local_max
from skimage.morphology import watershed
from scipy import ndimage
import numpy as np
import imutils
import cv2

image_dir = "/home/rahul/Desktop/img-708/"

img = cv2.imread(image_dir+'side_left.jpg')

lower = np.array([0, 48, 80], dtype = "uint8")
upper = np.array([20, 255, 255], dtype = "uint8")

# keep looping over the frames in the video


# resize the frame, convert it to the HSV color space,
# and determine the HSV pixel intensities that fall into
# the speicifed upper and lower boundaries
frame = imutils.resize(img, width = 400)
converted = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
skinMask = cv2.inRange(converted, lower, upper)

# apply a series of erosions and dilations to the mask
# using an elliptical kernel
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 11))
skinMask = cv2.erode(skinMask, kernel, iterations = 2)
skinMask = cv2.dilate(skinMask, kernel, iterations = 2)

# blur the mask to help remove noise, then apply the
# mask to the frame
skinMask = cv2.GaussianBlur(skinMask, (3, 3), 0)
skin = cv2.bitwise_and(frame, frame, mask = skinMask)

# show the skin in the image along with the mask
cv2.imwrite(image_dir+'output.jpg', np.hstack([skin]))

#image = cv2.imshow(np.hstack([skin])
image_dir = "/home/rahul/Desktop/img-708/"

image = cv2.imread(image_dir+'output.jpg')
#image = cv2.imread(pass)
shifted = cv2.pyrMeanShiftFiltering(image, 21, 51)
cv2.imshow("Input", image)

# convert the mean shift image to grayscale, then apply
# Otsu's thresholding
gray = cv2.cvtColor(shifted, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255,
    cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("Thresh", thresh)

# find contours in the thresholded image
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
    cv2.CHAIN_APPROX_SIMPLE)[-2]
print("[INFO] {} unique contours found".format(len(cnts)))

# loop over the contours
for (i, c) in enumerate(cnts):
    # draw the contour
    ((x, y), _) = cv2.minEnclosingCircle(c)
    cv2.putText(image, "#{}".format(i), (int(x) - 10, int(y)),
        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
    cv2.drawContours(image, [c], -1, (0, 255, 0), 2)

# show the output image
cv2.imshow("Image", image)
cv2.waitKey(0)

原始图片

enter image description here

输出我的代码图片:

enter image description here

1 个答案:

答案 0 :(得分:1)

我认为脚总是处于这个方向(没有旋转,没有颠倒)。

要保持最大轮廓,您可以:

  • 迭代轮廓并使用:cv2.contourArea
  • 计算轮廓区域
  • 迭代轮廓并使用cv2.boundingRect获取边界矩形以保持轮廓具有最大的边界框区域

使用cv2.boundingRect,您可以同时获得边界矩形的宽度,因此" global"脚的长度。

如果你想要弧长,一个可能的(也是更棘手的)解决方案是找到底部极值点然后迭代轮廓点并仅在这些极值点之间存储轮廓点。

可以使用cv2.arcLength计算弧长。

带有边界矩形和极值点的图像结果:

enter image description here

底部轮廓点的图像结果:

enter image description here

我得到了:

bounding rectangle width: 208 px
approximate arc length: 237.811 px

但是你必须记住,如果没有图像中的校准物体和单个相机,你将无法以厘米为单位检索尺寸,只能以像素为单位。

编辑:因为我没有Python,所以要求C ++中的源代码,应该很容易翻译成Python。

警告:可能无法使用更多通用或其他数据的特定和普通代码。

获取最大轮廓索引的简单代码:

size_t id_max_area = 0;
double max_area = 0.0;
for(size_t i = 0; i < contours.size(); i++) {
    double area = cv::contourArea(contours[i]);
    if(max_area < area) {
        max_area = area;
        id_max_area = i;
    }
}

获得极值点的(棘手的)代码:

cv::Point bottom_left(img.cols, 0), bottom_right(0, 0);
for(size_t i = 0; i < contours[id_max_area].size(); i++) {
    cv::Point contour_pt = contours[id_max_area][i];
    if(bottom_left.x > contour_pt.x)
        bottom_left.x = contour_pt.x;

    if(bottom_left.y < contour_pt.y)
        bottom_left.y = contour_pt.y;

    if(bottom_right.x < contour_pt.x)
        bottom_right.x = contour_pt.x;

    if(bottom_right.y < contour_pt.y)
        bottom_right.y = contour_pt.y;
}

保持底部轮廓点的(也很棘手)代码:

std::vector<cv::Point> bottom_contour;
for(size_t i = 0; i < contours[id_max_area].size(); i++) {
    cv::Point contour_pt = contours[id_max_area][i];
    if(contour_pt.x >= bottom_left.x && contour_pt.x <= bottom_right.x
        && contour_pt.y > bottom_left.y - 15) {
        bottom_contour.push_back(contour_pt);
    }
}
double length = cv::arcLength(bottom_contour, false);