LoginSignup
3
6

More than 3 years have passed since last update.

[OpenCV] リアルタイムで物体の輪郭を抽出する

Posted at

はじめに

OpenCVによる画像処理の基礎を整理します。
100本ノックのように、毎日追加していきたいと思います。

やりたいこと

写真や動画の物体の輪郭を抽出したいと思います。

輪郭抽出までの手順

  1. 画像を読み込む。(動画の場合、各フレームを読み込む。)
  2. ノイズ除去のため、GaussianBlurを行う。
  3. ColorをGrayScaleに変換する。
  4. Canny変換を行う。この時、Threshold1,2で調節を行う。(大事!)
  5. Dilation(拡張処理)を行う。
  6. Contourを検出する。
  7. 元の画像に検出したContourを描画する。

実行結果

[オリジナル動画、GaussianBlur処理後、GrayScaleh変換
Canny変換、Dilation処理、輪郭抽出描画]

bandicam-2020-12-02-17-52-01-508.gif

全体コード


import cv2
import numpy as np

frameWidth = 640
frameHeight = 480

cap = cv2.VideoCapture('videos/rectangle.mp4')
#cap = cv2.VideoCapture(0)

# Properties
cap.set(3, frameWidth)
cap.set(4, frameHeight)


def empty(a):
    pass


cv2.namedWindow('Parameters')
cv2.resizeWindow('Parameters', 1600, 400)
cv2.createTrackbar('Threshold1', 'Parameters', 0, 255, empty)
cv2.createTrackbar('Threshold2', 'Parameters', 0, 255, empty)
cv2.createTrackbar('Area', 'Parameters', 5000, 30000, empty)


def stackImages(scale, imgArray):
    rows = len(imgArray)
    cols = len(imgArray[0])
    rowsAvailable = isinstance(imgArray[0], list)
    width = imgArray[0][0].shape[1]
    height = imgArray[0][0].shape[0]
    if rowsAvailable:
        for x in range(0, rows):
            for y in range(0, cols):
                if imgArray[x][y].shape[:2] == imgArray[0][0].shape[:2]:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)
                else:
                    imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]),
                                                None, scale, scale)
                if len(imgArray[x][y].shape) == 2: imgArray[x][y] = cv2.cvtColor(imgArray[x][y], cv2.COLOR_GRAY2BGR)
        imageBlank = np.zeros((height, width, 3), np.uint8)
        hor = [imageBlank] * rows
        hor_con = [imageBlank] * rows
        for x in range(0, rows):
            hor[x] = np.hstack(imgArray[x])
        ver = np.vstack(hor)
    else:
        for x in range(0, rows):
            if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
                imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)
            else:
                imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None, scale, scale)
            if len(imgArray[x].shape) == 2: imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)
        hor = np.hstack(imgArray)
        ver = hor
    return ver

def getContours(img, imgContour):
    contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    #cv2.findContours(入力画像、contour retrieval mode, 輪郭研修津方法)
    for cnt in contours:
        area = cv2.contourArea(cnt)
        areaMin = cv2.getTrackbarPos("Area", "Parameters")
        if area > areaMin:
            #輪郭描画
            cv2.drawContours(imgContour, cnt, -1, (255, 0, 255), 7)
            peri = cv2.arcLength(cnt, True)
            approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
            print(len(approx))
            x, y, w, h = cv2.boundingRect(approx)
            cv2.rectangle(imgContour, (x, y), (x + w, y + h), (0, 255, 0), 5)

            cv2.putText(imgContour, "Points: " + str(len(approx)), (x + w + 20, y + 20), cv2.FONT_HERSHEY_COMPLEX, .7,
                        (0, 255, 0), 2)
            cv2.putText(imgContour, "Area: " + str(int(area)), (x + w + 20, y + 45), cv2.FONT_HERSHEY_COMPLEX, 0.7,
                        (0, 255, 0), 2)

while True:
    ret, img = cap.read()
    img = cv2.resize(img, (frameWidth, frameHeight))
    imgContour = img.copy()

    # Gaussian Blur
    imgBlur = cv2.GaussianBlur(img, (7, 7), 1)
    # Gray
    imgGray = cv2.cvtColor(imgBlur, cv2.COLOR_BGR2GRAY)
    # Canny
    threshold1 = cv2.getTrackbarPos('Threshold1', 'Parameters')
    threshold2 = cv2.getTrackbarPos('Threshold2', 'Parameters')
    imgCanny = cv2.Canny(imgGray, threshold1=threshold1, threshold2=threshold1)
    # Dialation
    kernel = np.ones((5, 5))
    imgDil = cv2.dilate(imgCanny, kernel=kernel, iterations=1)
    #Contours
    getContours(imgDil, imgContour)


    imgStack = stackImages(0.8, ([img, imgBlur, imgGray],
                                 [imgCanny, imgDil, imgContour]))
    cv2.imshow('Result', imgStack)

    # qを押すと止まる。
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

3
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6