본문 바로가기
AI/컴퓨터 비전

10. 레이블링

by 사라리24 2024. 7. 23.

1. 레이블링

- 이진화, 모폴로지를 수행하면 객체와 배경 영역을 구분할 수 있게됨
- 객체 단위 분석을 통해 각 객체를 분할하여 특징을 분석하고 객체의 위치, 크기 정보, 모양 분석, ROI 추출등이 가능함
- 서로 연결되어 이쓴 객체 픽셀에 고유번호를 할당하여 영역 기반 모양분석, 레이블맵, 바운딩 박스 픽셀 개수, 무게 중심, 좌표 등을 반환할 수 있게 함

 

◼ 레이블링


       
          cv2.connectedComponents(영상, 레이블맵)
          레이블맵: 픽셀 연결 관계(4방향 연결, 8방향 연결)
          return: 객체 객수, 레이블 맵 행렬

 

 

 

 

 예제: 문자 잡아내기

       

      import cv2

      img = cv2.imread('./keyboard.bmp', cv2.IMREAD_GRAYSCALE)

      # 이진화(thresholding) 처리
      # cv2.threshold() 함수를 사용하여 Otsu의 이진화 방법으로 이진 이미지를 생성합니다.
      _, img_bin = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

      # 회색조 이미지를 BGRA 포맷으로 변환
      # 이 단계는 나중에 각 성분을 다른 색상으로 표시하기 위해 수행됩니다.
      dst = cv2.cvtColor(img, cv2.COLOR_GRAY2BGRA)

      # 연결된 성분 분석
      # cv2.connectedComponentsWithStats() 함수는 이진 이미지에서 연결된 성분을 분석하여
      # 그 개수(cnt), 레이블(labels), 통계(stats), 중심점(centroids)을 반환합니다.
      cnt, labels, stats, centroids = cv2.connectedComponentsWithStats(img_bin)
      print(cnt)
      print(labels)
      print(stats)
      print(centroids)

      # 면적이 30보다 작은 성분은 무시
      for i in range(1, cnt):
          (x, y, w, h, area) = stats[i]
          if area < 30:
              continue
          # 성분을 둘러싸는 사각형 그리기 (색상: 노란색, 두께: 1픽셀)
          cv2.rectangle(dst, (x,y,w,h),(0, 255,255))

      cv2.imshow('img', img)
      cv2.imshow('img_bin', img_bin)
      cv2.imshow('dst', dst)
      cv2.waitKey()



 







 

 

 

2. 객체의 외곽선 검출

 

 

객체의 외곽선 검출


       
      cv2.findContours(영상, 검출모드, 외각선 죄표 근사화 방법)

     * 검출모드 
     RETR_EXRETNAL: 객체 외부 외곽선만 검출
     RETR_LIST : 객체 외부, 내부 외곽선 모두 검출
     RETR_CCOMP : 모든 외곽선 검출, 2단계 계층 구조를 구성
     RETR_TREE : 모든 외곽선 검출, 전체 계층 구조를 구선


- 레이블링과 함께 영상에서 객체의 정보를 검출하는 방법중 하나
- 이진화 된 영상에서 검출되며, 배경 영역과 닿아 있는 픽셀을 찾아 외곽선으로 인식
- 외곽선은 객체 외부 뿐 아니라 내부에서도 생길 수 있음

 

 

외곽선 좌표 근사화 방법


      
        cv2.drawContours(영상, 외곽선 좌표 정보, 외곽선 인덱스, 색상, 두께)
        외곽선 인덱스
: -1을 지정하면 모든 외곽선을 그림



외곽선 점들의 저장 방식과 정확도를 정의

 

 

외곽선 길이 구하기

       

     cv2.arcLength(외곽선 좌표, 페곡선 여부)

 

 

 

면적 구하기

       

      cv2.contourArea(외곽선 좌표, False)


 

 

바운딩 박스 구하기

       

       cv2.boundingRect(외곽선 좌표)


 

 

예제: 외곽선을 찾고, 무작위 색상으로 외곽선을 그리기


       
        import cv2
        import random

        img = cv2.imread('./contours.bmp', cv2.IMREAD_GRAYSCALE)

        # 외곽선 찾기
        # cv2.findContours() 함수는 이진화된 이미지에서 외곽선을 찾아 반환합니다.
        # cv2.RETR_CCOMP: 외곽선을 계층 구조로 반환합니다.
        # cv2.CHAIN_APPROX_NONE: 모든 외곽선 점을 반환합니다.
        contours, _ = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)

        # 회색조 이미지를 BGR 포맷으로 변환
        dst = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

        # 무작위 색상 생성
        # random.randint() 함수를 사용하여 0부터 255 사이의 임의의 값을 생성하여 색상을 만듭니다.
        color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))

        # 외곽선 그리기
        # cv2.drawContours() 함수는 외곽선을 그립니다.
        # dst: 외곽선을 그릴 이미지.
        # contours: 외곽선 정보.
        # -1: 모든 외곽선을 그립니다.
        # color: 외곽선을 그릴 색상.
        # 3: 외곽선의 두께.
        cv2.drawContours(dst, contours, -1, color, 3)

        cv2.imshow('img', img)
        cv2.imshow('dst', dst)
        cv2.waitKey()


 


예제: 이진화 후, 외곽선을 검출하여 외곽선을 표기하기


       
            # milkdrop.bmp 영상을 이용하여 이진화를 시키고, 외곽선을 검출하여 외곽선을 랜덤한 색상으로 표기
            import numpy as np
           
            img = cv2.imread('./milkdrop.bmp', cv2.IMREAD_GRAYSCALE)
            _, img_bin = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
            contours, _ = cv2.findContours(img_bin, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
           
            h, w = img.shape[:2]
            dst = np.zeros((h, w, 3), np.uint8)
           
            for i in range(len(contours)):
                color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
                cv2.drawContours(dst, contours, i, color, 2)
           
            cv2.imshow('img', img)
            cv2.imshow('img_bin', img_bin)
            cv2.imshow('dst', dst)
            cv2.waitKey()


 

 

 

 

3. 외곽선의 근사화

검출한 외곽선 정보를 분석하여 정점수가 적은 외곽선 또는 다각형으로 표현할 수 있게 만드는 것

 

외곽선 근사화


       
        cv2.drawContours(영상, 외곽선 좌표 정보, 외곽건 인덱스, 색상, 두께)
        외곽선 인덱스
: -1을 지정하면 모든 외곽선을 그림
 
 
근사화 정밀도 조절: 입력 외곽선과 근사화된 외곽선 사이의 최대거리, 값이 작을수록 다각형이 정확해지고, 꼭지점 수가 늘어남

 

 

블록부분이 있는지 여부



        cv2.arcLength(외곽선 좌표, 페곡선 여부)
 
 
contour에 오목한 부분이 있는지 체크(있으면 true, 없으면 False)

 

 

블록외피를 계산


       
         cv2.contourArea(외곽선 좌표, False)


contour에 있는 오복한 부분을 제거

 

 

예제: 다각형의 종류를 식별해서 표기하기


       
        import cv2
        import math

        def setLevel(img, pts, label):
            """
            주어진 다각형의 바운딩 박스를 그린 후 레이블을 추가하는 함수.
            img: 원본 이미지.
            pts: 다각형의 외곽선 좌표.
            label: 다각형의 레이블 (TRI, RECT, CIR, NONAME).
            """
            # 다각형의 바운딩 박스 계산
            (x, y, w, h) = cv2.boundingRect(pts)
            pt1 = (x, y)
            pt2 = (x + w, y + h)
            # 바운딩 박스 그리기
            cv2.rectangle(img, pt1, pt2, (0, 0, 255), 2)
            # 레이블 추가
            cv2.putText(img, label, pt1, cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255))

        img = cv2.imread('./polygon.bmp')

        gray = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)

        # 이진화 처리 (배경은 흰색, 다각형은 검은색으로 반전)
        _, img_bin = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
        # 외곽선 찾기 (가장 바깥쪽 외곽선만 찾음)
        contours, _ = cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

        # 각 외곽선에 대해 반복
        for pts in contours:
            # 작은 영역은 무시
            if cv2.contourArea(pts) < 200:
                continue
            # 외곽선을 근사화하여 꼭짓점 개수 계산
            approx = cv2.approxPolyDP(pts, cv2.arcLength(pts, True) * 0.02, True)
            vtc = len(approx)

            # 다각형의 종류에 따라 레이블 지정
            if vtc == 3:
                setLevel(img, pts, 'TRI')
            elif vtc == 4:
                setLevel(img, pts, 'RECT')
            else:
                # 원인지 확인 (형상 비율 계산)
                length = cv2.arcLength(pts, True)
                area = cv2.contourArea(pts)
                ratio = 4. * math.pi * area / (length * length)
                if ratio > 0.70:
                    setLevel(img, pts, 'CIR')
                else:
                    setLevel(img, pts, 'NONAME')

        cv2.imshow('img', img)
        cv2.waitKey()




- cv2.THRESH_BINARY: 도형이 검정색



- cv2.THRESH_BINARY_INV: 도형이 흰색


 

 

'AI > 컴퓨터 비전' 카테고리의 다른 글

12. VGG19 | 분류  (1) 2024.07.24
11. OCR  (1) 2024.07.23
09. 모폴로지 변환  (0) 2024.07.23
08. 필터링, 블러링  (0) 2024.07.22
07. 이미지 유사도, 영상의 변환  (0) 2024.07.18