๐Ÿ˜Ž ๊ณต๋ถ€ํ•˜๋Š” ์ง•์ง•์•ŒํŒŒ์นด๋Š” ์ฒ˜์Œ์ด์ง€?

5. OpenCV๋กœ ์ด๋ฏธ์ง€ ์ฐจ์ด ๋ถ„์„ํ•˜๊ธฐ – “์ฒœ์ฒด ์ด๋ฏธ์ง€๋กœ ๋ช…์™•์„ฑ์„ ์ฐพ์•„๋ณด์ž” ๋ณธ๋ฌธ

๐Ÿ‘ฉ‍๐Ÿ’ป IoT (Embedded)/Image Processing

5. OpenCV๋กœ ์ด๋ฏธ์ง€ ์ฐจ์ด ๋ถ„์„ํ•˜๊ธฐ – “์ฒœ์ฒด ์ด๋ฏธ์ง€๋กœ ๋ช…์™•์„ฑ์„ ์ฐพ์•„๋ณด์ž”

์ง•์ง•์•ŒํŒŒ์นด 2022. 10. 20. 13:50
728x90
๋ฐ˜์‘ํ˜•

 

221020 ์ž‘์„ฑ

<๋ณธ ๋ธ”๋กœ๊ทธ๋Š”์‹ค์ „ ํŒŒ์ด์ฌ ํ•ธ์ฆˆ์˜จ ํ”„๋กœ์ ํŠธ์˜ github ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ๊ณต๋ถ€ํ•˜๋ฉฐ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค>

https://www.onlybook.co.kr/m/entry/python-projects

 

์‹ค์ „ ํŒŒ์ด์ฌ ํ•ธ์ฆˆ์˜จ ํ”„๋กœ์ ํŠธ

์‹ค์ „ ํŒŒ์ด์ฌ ํ•ธ์ฆˆ์˜จ ํ”„๋กœ์ ํŠธ ๋ฌธ์ œ ํ•ด๊ฒฐ๊ณผ ์‹ค๋ฌด ์‘์šฉ๋ ฅ์„ ํ‚ค์šฐ๊ธฐ ์œ„ํ•œ ๋‚˜๋งŒ์˜ ํŒŒ์ด์ฌ ํฌํŠธํด๋ฆฌ์˜ค ๋งŒ๋“ค๊ธฐ ๋ฆฌ ๋ณธ ์ง€์Œ | ์˜คํ˜„์„ ์˜ฎ๊น€ 420์ชฝ | 28,000์› | 2022๋…„ 5์›” 31์ผ ์ถœ๊ฐ„ | 185*240*20 | ISBN13 9791.

www.onlybook.co.kr

https://github.com/rlvaugh/Real_World_Python

 

GitHub - rlvaugh/Real_World_Python: Code and supporting files for book Real World Python

Code and supporting files for book Real World Python - GitHub - rlvaugh/Real_World_Python: Code and supporting files for book Real World Python

github.com

 

 

๐Ÿ˜Š OpenCV์™€ NumPy

: ํด๋ผ์ด๋“œ ํ†ฐ๋ณด๊ฐ€ 1930๋…„ ๋ช…์™•์„ฑ์„ ๋ฐœ๊ฒฌํ•  ๋•Œ ์‚ฌ์šฉํ•œ ์žฅ์น˜์ธ ‘๋ฐ˜์ง ๋น„๊ต์ •’์„ ๋ณต์›

ํ˜„๋Œ€์ ์ธ ์ปดํ“จํ„ฐ ๋น„์ „ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•ด ์ž๋™์œผ๋กœ ํ–‰์„ฑ์ด๋‚˜ ์šด์„๊ณผ ๊ฐ™์ด ๋ณ„ ์‹œ์•ผ์—์„œ ์ด๋™ ์ค‘์ธ ์ˆœ๊ฐ„์ ์ธ ์ฒœ์ฒด๋ฅผ ์ฐพ์•„๋‚ธ๋‹ค.

# """ํŽ˜์–ด๋ง๋œ ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋Š” 2๊ฐœ์˜ ํด๋”๋ฅผ ์ˆœํ™˜ํ•˜๊ณ  ์ด๋ฏธ์ง€๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ๊นœ๋ฐ•์ž„"""
def main():
    night1_files = sorted(os.listdir('./night_1'))
    night2_files = sorted(os.listdir('./night_2'))             
    path1 = Path.cwd() / './night_1'
    path2 = Path.cwd() / './night_2'
    path3 = Path.cwd() / './night_1_registered'

    for i, _ in enumerate(night1_files):    
        img1 = cv.imread(str(path1 / night1_files[i]), cv.IMREAD_GRAYSCALE)
        img2 = cv.imread(str(path2 / night2_files[i]), cv.IMREAD_GRAYSCALE)

        print("Comparing {} to {}.\n".format(night1_files[i], night2_files[i]))

        # ํ•ต์‹ฌ ํฌ์ธํŠธ์™€ ๊ทธ๋“ค ์‚ฌ์ด์˜ ๊ฐ€์žฅ ์ข‹์€ ์ผ์น˜๋ฅผ ์ฐพ๊ธฐ
        kp1, kp2, best_matches = find_best_matches(img1, img2)
        img_match = cv.drawMatches(img1, kp1, img2, kp2,
                                   best_matches, outImg=None)
        
        # ๋‘ ์ด๋ฏธ์ง€ ์‚ฌ์ด์— ์„ ์„ ๊ทธ๋ฆผ
        height, width = img1.shape
        cv.line(img_match, (width, 0), (width, height), (255, 255, 255), 1)
        QC_best_matches(img_match)      # ๋ฌด์‹œํ•˜๋ ค๋ฉด ์ฃผ์„ ์ฒ˜๋ฆฌ

        # ํ‚คํฌ์ธํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์™ผ์ชฝ ์ด๋ฏธ์ง€๋ฅผ ๋“ฑ๋ก   
        img1_registered = register_image(img1, img2, kp1, kp2, best_matches)

        # QC ๋“ฑ๋ก ๋ฐ ๋“ฑ๋ก๋œ ์ด๋ฏธ์ง€ ์ €์žฅ(์„ ํƒ ๋‹จ๊ณ„):
        blink(img1, img1_registered, 'Check Registration', num_loops=5)  
        out_filename = '{}_registered.png'.format(night1_files[i][:-4])
        cv.imwrite(str(path3 / out_filename), img1_registered)      # ๋ฎ์–ด์“ด๋‹ค

        cv.destroyAllWindows()

        # ๊นœ๋ฐ•์ž„ ๋น„๊ต๊ธฐ ์‹คํ–‰
        blink(img1_registered, img2, 'Blink Comparator', num_loops=15)


# """๋‘ ์ด๋ฏธ์ง€์— ๋Œ€ํ•œ ํ‚คํฌ์ธํŠธ ๋ชฉ๋ก๊ณผ ๊ฐ€์žฅ ์ž˜ ์ผ์น˜ํ•˜๋Š” ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜"""
def find_best_matches(img1, img2):
    orb = cv.ORB_create(nfeatures=100)      # ORB ๊ฐœ์ฒด๋ฅผ ์‹œ์ž‘

    # ORB๋กœ ํ‚คํฌ์ธํŠธ์™€ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ์ฐพ๊ธฐ
    kp1, desc1 = orb.detectAndCompute(img1, mask=None)
    kp2, desc2 = orb.detectAndCompute(img2, mask=None)
    
    # Brute Force Matcher๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ‚คํฌ์ธํŠธ ์ผ์น˜๋ฅผ ์ฐพ๊ธฐ
    bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck=True)
    matches = bf.match(desc1, desc2)

    # ๊ฑฐ๋ฆฌ์˜ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ผ์น˜ ํ•ญ๋ชฉ์„ ์ •๋ ฌํ•˜๊ณ  ์ตœ์ƒ์˜ n๊ฐœ ์ผ์น˜ ํ•ญ๋ชฉ์„ ์œ ์ง€
    matches = sorted(matches, key=lambda x: x.distance)
    best_matches = matches[:MIN_NUM_KEYPOINT_MATCHES]
              
    return kp1, kp2, best_matches

# """์ปฌ๋Ÿฌ ๋ผ์ธ์œผ๋กœ ์—ฐ๊ฒฐ๋œ ์ตœ์ƒ์˜ ํ‚คํฌ์ธํŠธ ์ผ์น˜๋ฅผ ๊ทธ๋ฆฐ๋‹ค"""
def QC_best_matches(img_match):
    cv.imshow('Best {} Matches'.format(MIN_NUM_KEYPOINT_MATCHES), img_match)
    cv.waitKey(2500)            # ์ฐฝ์„ 2.5์ดˆ ๋™์•ˆ ํ™œ์„ฑ ์ƒํƒœ๋กœ ์œ ์ง€
        
# """๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์— ๋“ฑ๋ก๋œ ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ ๋ฐ˜ํ™˜"""
def register_image(img1, img2, kp1, kp2, best_matches):
    if len(best_matches) >= MIN_NUM_KEYPOINT_MATCHES:
        src_pts = np.zeros((len(best_matches), 2), dtype=np.float32)
        dst_pts = np.zeros((len(best_matches), 2), dtype=np.float32)

        for i, match in enumerate(best_matches):
            src_pts[i, :] = kp1[match.queryIdx].pt
            dst_pts[i, :] = kp2[match.trainIdx].pt
        
        # findHomography : ๋‘ ํ‰๋ฉด ์‚ฌ์ด์˜ ํˆฌ์‹œ ๋ณ€ํ™˜(Perspective transform)์„ ์˜๋ฏธ, homography matrix, H ์ถ”์ถœ
        h_array, mask = cv.findHomography(src_pts, dst_pts, cv.RANSAC)
        height, width = img2.shape       # ์ด๋ฏธ์ง€ 2์˜ ์น˜์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ
        # warpPerspective : ์›๊ทผ ๋งต ํ–‰๋ ฌ์— ๋Œ€ํ•œ ๊ธฐํ•˜ํ•™์  ๋ณ€ํ™˜์„ ์ˆ˜ํ–‰
        img1_warped = cv.warpPerspective(img1, h_array, (width, height))

        return img1_warped

    else:
        print("WARNING: Number of keypoint matches < {}\n".format
              (MIN_NUM_KEYPOINT_MATCHES))
        return img1

# """๋‘ ๊ฐœ์˜ ์ด๋ฏธ์ง€๋กœ ๊นœ๋ฐ•์ž„ ๋น„๊ต๊ธฐ๋ฅผ ๋ณต์ œ"""
def blink(image_1, image_2, window_name, num_loops):
    for _ in range(num_loops):
        cv.imshow(window_name, image_1)
        cv.waitKey(330)
        cv.imshow(window_name, image_2)
        cv.waitKey(330)
        
if __name__ == '__main__':
    main()

 

๐Ÿ˜Š WSL2 UBUNTU GUI๋กœ ์ด๋ฏธ์ง€ ์ฐจ์ด ๋ถ„์„ํ•˜๊ธฐ

https://qkrm.tistory.com/18

 

WSL2 UBUNTU GUI๋กœ ์‚ฌ์šฉํ•˜๊ธฐ

www.youtube.com/watch?v=IL7Jd9rjgrM&list=LL&index=1 dev.to/darksmile92/linux-on-windows-wsl-with-desktop-environment-via-rdp-522g Linux on Windows: WSL with Desktop Environment via RDP WSL (Windows..

qkrm.tistory.com

๊ณ ๋Œ€๋กœ ๋”ฐ๋ผํ•˜์„ธ์šฉ

 

 

 

 

728x90
๋ฐ˜์‘ํ˜•
Comments