๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

AI/Computer Vision

[Computer Vision] Skeletonization

728x90
๋ฐ˜์‘ํ˜•
๐Ÿ‘€ ๋ณธ ์˜ˆ์ œ๋Š” Window10์˜ VSCode, Python3.11.0๋กœ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

Skeletonization์€ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ์—์„œ ๊ฐ์ฒด์˜ ํ˜•ํƒœ๋ฅผ ๋‹จ์ˆœํ™”ํ•˜์—ฌ ๊ทธ ๊ตฌ์กฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ธฐ๋ฒ•์ด๋‹ค.

 

์ด ๊ณผ์ •์€ ์ฃผ๋กœ ์ด์ง„ ์ด๋ฏธ์ง€์—์„œ ์‚ฌ์šฉ๋˜๋ฉฐ, ๊ฐ์ฒด์˜ ์œค๊ณฝ์„ ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ๋‘๊ป˜๋ฅผ ์ค„์—ฌ์„œ ์„ ์˜ ํ˜•ํƒœ๋กœ ํ‘œํ˜„ํ•œ๋‹ค.

 

import cv2
import numpy as np

def skeletonize(img):
    """ OpenCV function to return a skeletonized version of img, a Mat object"""

    #  hat tip to http://felix.abecassis.me/2011/09/opencv-morphological-skeleton/

    img = img.copy() # don't clobber original
    skel = img.copy()

    skel[:,:] = 0
    kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3,3))

    while True:
        eroded = cv2.morphologyEx(img, cv2.MORPH_ERODE, kernel)
        temp = cv2.morphologyEx(eroded, cv2.MORPH_DILATE, kernel)
        temp  = cv2.subtract(img, temp)
        skel = cv2.bitwise_or(skel, temp)
        img[:,:] = eroded[:,:]
        if cv2.countNonZero(img) == 0:
            break

    return skel


# ์ด๋ฏธ์ง€ ์ฝ๊ธฐ
image = cv2.imread('human.png', cv2.IMREAD_GRAYSCALE)
h,w = image.shape
# resize
image = cv2.resize(image,(int(w//2),int(h//2)),interpolation=cv2.INTER_LANCZOS4)
# ์Šค์ผˆ๋ ˆํ† ๋‚˜์ด์ฆˆ ์ˆ˜ํ–‰
skeleton = skeletonize(image)

# ๊ฒฐ๊ณผ ์ถœ๋ ฅ
cv2.imshow('Original Image', image)
cv2.imshow('Skeleton', skeleton)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

Skeletonization ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋Œ€ํ‘œ์ ์œผ๋กœ Zhang-Suen ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ Guo-Hall ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์žˆ๋‹ค.

 

Zhang-Suen

Zhang-Suen ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋ฐ˜๋ณต์ ์ธ ํ˜•ํƒœํ•™์  ์—ฐ์‚ฐ์„ ํ†ตํ•ด ์Šค์ผˆ๋ ˆํ†ค์„ ์ƒ์„ฑํ•œ๋‹ค.

import numpy as np
import cv2
from numba import jit,prange

@jit
def thinning_iteration(im, iter):
    I, M = im.copy(), np.zeros(im.shape, np.uint8)
    for i in prange(1, im.shape[0] - 1):
        for j in prange(1, im.shape[1] - 1):
            p2 = I[i-1, j]
            p3 = I[i-1, j+1]
            p4 = I[i, j+1]
            p5 = I[i+1, j+1]
            p6 = I[i+1, j]
            p7 = I[i+1, j-1]
            p8 = I[i, j-1]
            p9 = I[i-1, j-1]

            A = (p2 == 0 and p3 == 1) + (p3 == 0 and p4 == 1) + \
                (p4 == 0 and p5 == 1) + (p5 == 0 and p6 == 1) + \
                (p6 == 0 and p7 == 1) + (p7 == 0 and p8 == 1) + \
                (p8 == 0 and p9 == 1) + (p9 == 0 and p2 == 1)
            B = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9
            m1 = p2 * p4 * p6 if iter == 0 else p2 * p4 * p8
            m2 = p4 * p6 * p8 if iter == 0 else p2 * p6 * p8

            if A == 1 and B >= 2 and B <= 6 and m1 == 0 and m2 == 0:
                M[i, j] = 1

    return I & ~M

def thinning(src):
    dst = src.copy() // 255
    prev = np.zeros(src.shape, np.uint8)
    diff = None

    while True:
        dst = thinning_iteration(dst, 0)
        dst = thinning_iteration(dst, 1)
        diff = np.abs(dst - prev)
        prev = dst.copy()
        if np.sum(diff) == 0:
            break

    return dst * 255

# ์ด๋ฏธ์ง€ ์ฝ๊ธฐ
image = cv2.imread('h.png', cv2.IMREAD_GRAYSCALE)
h, w = image.shape
# resize
image = cv2.resize(image, (int(w // 2), int(h // 2)), interpolation=cv2.INTER_LANCZOS4)
# ์ด์ง„ํ™”
_, bw2 = cv2.threshold(image, 10, 255, cv2.THRESH_BINARY)
# Zhang-Suen ์Šค์ผˆ๋ ˆํ†คํ™” ์ˆ˜ํ–‰
bw2 = thinning(bw2)

# ๊ฒฐ๊ณผ ์ถœ๋ ฅ
cv2.imshow("original",image)
cv2.imshow('Skeleton', bw2)  # ์Šค์ผˆ๋ ˆํ†ค์„ 0-255 ๋ฒ”์œ„๋กœ ๋ณ€ํ™˜
cv2.waitKey(0)
cv2.destroyAllWindows()

 

 

 

Guo-Hall

Guo-Hall ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ Zhang-Suen๊ณผ ์œ ์‚ฌํ•˜๋‚˜, ๋‘ ๊ฐœ์˜ ๋ฐ˜๋ณต ๋‹จ๊ณ„๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๊ณ , ๊ฐ ๋‹จ๊ณ„์—์„œ ๋” ๋งŽ์€ ์กฐ๊ฑด์„ ๊ณ ๋ คํ•˜์—ฌ ํ”ฝ์…€์„ ์ œ๊ฑฐํ•˜๋ฏ€๋กœ, ๋” ์ •๊ตํ•œ ์Šค์ผˆ๋ ˆํ†ค์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

# pip install thinning-py3

import cv2
import thinning
from copy import copy
img = cv2.imread("h.png",cv2.IMREAD_GRAYSCALE)
img_ = copy(img)
thinned = thinning.guo_hall_thinning(img_)
cv2.imshow("original",img)
cv2.imshow("guohall",thinned)

cv2.waitKey(0)
cv2.destroyAllWindows()

 

 

 

์ด๋ฟ๋งŒ ์•„๋‹ˆ๋ผ Skeletonization์€ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—๋„ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ œ๊ณต๋œ๋‹ค.

import cv2
from skimage.morphology import skeletonize
import numpy as np
image = cv2.imread('h.png', cv2.IMREAD_GRAYSCALE)

ske = skeletonize(image)
skeleton_uint8 = (ske * 255).astype(np.uint8)

cv2.imshow("original",image)
cv2.imshow('Skeleton', skeleton_uint8)  # ์Šค์ผˆ๋ ˆํ†ค์„ 0-255 ๋ฒ”์œ„๋กœ ๋ณ€ํ™˜
cv2.waitKey(0)
cv2.destroyAllWindows()

 

728x90
๋ฐ˜์‘ํ˜•

'AI > Computer Vision' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Computer Vision] ์ด๋ฏธ์ง€ ์œ ์‚ฌ๋„  (0) 2024.09.21
[Computer Vision] Segmentation  (0) 2024.09.19
[Computer Vision] Depth  (0) 2024.09.15
[Computer Vision] Trapped-ball Segmentation  (0) 2024.09.14
[Computer Vision] IoU(Intersection over Union)  (0) 2024.09.12