OpenCV - 使用凸包和自适应阈值在手指上绘制轮廓

OpenCV - Draw contours on fingers using convex-hulls & adaptive thresholding

我是 OpenCV 的新手,我正在尝试使用网络摄像头沿着我的手的轮廓绘制简单的轮廓。我决定使用 cv2.adaptiveThreshold() 来处理相机适应手移动时的不同光强。一切似乎都很好,除了它正在努力寻找手指然后绘制闭合轮廓。 看这里:

我想尝试检测一个凸包并检测任何偏离它的东西。

我该怎么做才能最好?首先,我需要设法找到可能找不到奇怪的闭合轮廓,然后从那里开始?

这是代码,我为您修复了轨迹栏值:)

import cv2
import numpy as np

#####################################
winWidth = 640
winHeight = 840
brightness = 100

cap = cv2.VideoCapture(0)
cap.set(3, winWidth)
cap.set(4, winHeight)
cap.set(10, brightness)

kernel = (7, 7)


#######################################################################
def empty(a):
    pass


cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars", 640, 240)
cv2.createTrackbar("cVal", "TrackBars", 10, 40, empty)
cv2.createTrackbar("bSize", "TrackBars", 77, 154, empty)


def preprocessing(frame, value_BSize, cVal):
    imgGray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # mask = cv2.inRange(imgHsv, lower, upper)
    imgBlurred = cv2.GaussianBlur(imgGray, kernel, 4)
    gaussC = cv2.adaptiveThreshold(imgBlurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, value_BSize,
                                   cVal)
    imgDial = cv2.dilate(gaussC, kernel, iterations=3)
    imgErode = cv2.erode(imgDial, kernel, iterations=1)

    return imgDial


def getContours(imPrePro):
    contours, hierarchy = cv2.findContours(imPrePro, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    for cnt in contours:
        area = cv2.contourArea(cnt)
        if area > 60:
            cv2.drawContours(imgCon, cnt, -1, (0, 255, 0), 2, cv2.FONT_HERSHEY_SIMPLEX)
            peri = cv2.arcLength(cnt, True)
            approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)


#######################################################################################################

while cap.isOpened():
    success, frame = cap.read()
    cVal = cv2.getTrackbarPos("cVal", "TrackBars")
    bVal = cv2.getTrackbarPos("bVal", "TrackBars")
    value_BSize = cv2.getTrackbarPos("bSize", "TrackBars")
    value_BSize = max(3, value_BSize)
    if (value_BSize % 2 == 0):
        value_BSize += 1

    if success == True:
        frame = cv2.flip(frame, 1)
        imgCon = frame.copy()
        imPrePro = preprocessing(frame, value_BSize, cVal)
        getContours(imPrePro)
        cv2.imshow("Preprocessed", imPrePro)
        cv2.imshow("Original", imgCon)

        if cv2.waitKey(1) & 0xFF == ord("q"):
            cv2.destroyAllWindows()
            break

我使用的是光阈值,因此这可能会根据图像的不同而有所不同,但这是适用于此图像的方法。

import cv2
import numpy as np

# load image
img = cv2.imread("hand.jpg");

# lab
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB);
l,a,b = cv2.split(lab);

# threshold
thresh = cv2.inRange(l, 90, 255);

# contour
_, contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);

# filter contours by size
marked = img.copy();
cv2.drawContours(marked, contours, -1, (0, 255, 0), 3);

# show
cv2.imshow("marked", marked);
cv2.imshow("Thresh", thresh);
cv2.waitKey(0);

# save
cv2.imwrite("marked_hand.png", marked);

L*a*b color space 可以帮助找到比背景亮的物体。一个优点是 color space 与硬件无关,因此它应该从任何相机产生相对相似的结果。使用 OTSU 选项对图像进行阈值处理可以帮助它在不同的光照条件下工作,因为它会计算最佳阈值强度以分离图像中的亮区和暗区。显然它不是灵丹妙药,不会在所有情况下都能完美工作,尤其是在极端情况下,但只要你手的亮度与背景的亮度相对不同,它就应该可以工作。

lab = cv2.cvtColor(frame, cv2.COLOR_BGR2LAB)
tv, thresh = cv2.threshold(lab[:,:,0], 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
plt.imshow(thresh)

正确设置手的阈值后,您可以继续查找轮廓并根据需要进行分析。

注意:阈值图像中的伪影是由于从原始发布图像中删除绿色轮廓线造成的。

您是否研究过 google 的 mediapipe,作为 opencv 的替代品?

此外,我想知道在框架上添加一个细的底部黑色边框是否有助于轮廓环绕手腕。