OpenCV의 GrabCut을 사용해 보았습니다.

MYJlab 모험 달력 의 9일째입니다.

이것은 무엇인가



n번 달인데, 이미지의 전경 영역을 추출하기 위해 OpenCV의 GrabCut을 사용해 본 기사입니다.

배경



저의 프로그래밍 이외의 유일한 취미는 기타입니다만, 기타를 외형으로부터 간단하게 검색할 수 있는 서비스를 만들려고 합니다. 그 과정에서 기타 단체를 뽑아낸 이미지가 필요할 것 같아서, 배경을 삭제할 수 있는 수법 뭔가 없을까-라고 찾고 있었습니다.
특히 좋은 것을 찾지 못하면 세그멘테이션용 모델로 어떻게든 할 수 없을까라고 생각하고 있을 때 OpenCV의 GrabCut 간단하게 할 수 있는 것 같아서 시도해 보았습니다.

구현



구조에 대해서는 파이썬 튜토리얼 가 상세합니다.
수행하는 작업은 다음과 같습니다.
  • 이미지로드
  • 원하는 전경을 포함한 구형을 지정
  • GrabCut 실행
  • GrabCut 결과를 원본 이미지에 반영

  • 이번에는 기타 이미지를 무료 소재에서 가져 왔습니다.
  • htps // 응 sp sh. 이 m/p 쪽 s/YSt보키 FPVw

  • 이미지 로드



    위의 3개의 화상은 화상 사이즈가 크기 때문에 미리 작게 해 둡니다.
    def resize_image(filepath, width, height):
        img = Image.open(filepath)
        img.thumbnail((width, height),resample=Image.BICUBIC)
        return img
    IMG_BASE_PATH = './img/'
    filename = 'guitar.jpeg'
    WIDTH = 1000
    HEIGHT = 1000
    file_path = IMG_BASE_PATH + filename
    pillow_img = resize_image(file_path, WIDTH, HEIGHT)
    resized_image_path = f'{IMG_BASE_PATH}resized_{filename}'
    pillow_img.save(resized_image_path)
    

    크기 조정이 끝나면 OpenCV를 사용하여 다시 로드합니다. 사실은 Pillow로 불러온 이미지를 OpenCV의 이미지로 변환하는 방법이 있다고 생각합니다만, 이번은 이것으로 좋게 해 주세요.
    img = cv2.imread(resized_image_path)
    

    원하는 전경 둘러싸는 구형을 지정



    GrabCut은 대화식 방식으로 전경을 추출하는 기술입니다. 그래서 사용하는 인간이 어디에 원하는 전경이 포함되어 있는지를 지정해 줄 필요가 있습니다. 이번은 귀찮아서 이미지의 거의 전부를 직사각형으로 둘러싸겠습니다.
    # 引数はx座標, y座標, 幅, 高さ
    rect = (1,1, pillow_img.size[0],pillow_img.size[1])
    

    여기서 x 좌표와 y 좌표에서 0을 지정하면 GrabCut 실행시 다음 오류가 발생했습니다.
    ---------------------------------------------------------------------------
    error                                     Traceback (most recent call last)
    <ipython-input-46-73e975b54ddd> in <module>
          1 rect = (0,0, pillow_img.size[0],pillow_img.size[1])
    ----> 2 cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
    
    error: OpenCV(4.1.2) /io/opencv/modules/imgproc/src/grabcut.cpp:386: error: (-215:Assertion failed) !bgdSamples.empty() && !fgdSamples.empty() in function 'initGMMs'
    

    튜토리얼을 보면

    사용자는 먼저 초기 값으로 전경 영역 주위에 직사각형을 그립니다 (전경 물체는이 직사각형에서 튀어 나와서는 안됩니다).

    이번 경우는 튀어 나오지는 않지만 모든 영역을 둘러싸고 있기 때문에 안 되는 것 같아요.

    GrabCut 실행



    mask에 대한 numpy 배열과 GrabCut에 필요한 배열을 만듭니다.
    mask = np.zeros(img.shape[:2],np.uint8)
    
    bgdModel = np.zeros((1,65),np.float64)
    fgdModel = np.zeros((1,65),np.float64)
    

    반복 수는 튜토리얼 그대로 5에서 실행됩니다.
    cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
    

    GrabCut 결과를 원본 이미지에 반영



    반영하기 전에 GrabCut의 결과를 살펴 보겠습니다.
    GrabCut은 이미지의 픽셀별로 네 가지 분류를 수행합니다. 튜토리얼에 따르면 이 네 가지 분류는 다음과 같은 의미를

    마스크 화상 중의 화소치가 0의 화소는 배경, 1의 화소는 전경, 2의 화소는 배경다운, 3의 화소는 전경다운 화소를 의미합니다

    마스크의 0,2 부분을 검은 색으로 채우면 전경 이미지 만 얻을 수 있습니다.
    mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
    img = img*mask2[:,:,np.newaxis]
    

    결과



    처리 전





    처리 후





    대체로 좋은 느낌으로 잘라내고 있습니다만, 좌하의 배경과 바닥의 광택이 남아 버렸습니다. 진짜는 수정하는 것도 가능합니다만, 이번은 이 정밀도로 문제 없기 때문에 여기까지로 끝납니다.

    마지막으로



    OpenCV의 GrabCut을 사용해 보았습니다. 신경망을 사용하지 않고 여기까지 할 수있는 것에 놀랐습니다.
    이미지 사이즈에 따라서는 속도가 비정상적으로 느리거나 하기 때문에 앞으로는 거기를 어떻게든 해결할 수 없는지를 찾아 가고 싶습니다.

    참고로 한 사이트


  • htp://bs. 그래 cs. 푹 빠져. 아 c. jp/sd/메 m r/오야마타/오펜 CV/html/py_개별 ls/py_이 mgp로 c/py_g등 b t/py_g등 b t. HTML
  • htps : // 이 m / k의 k / ms / 63 에 32 아 f9c t f095d49
  • htps : //에서. 응 kmk. 메/py 텐-오펜 cv-bgr-rgb-cvt 코-r/
  • htps : // ky-오리하라. 하테나 bぉg. 코m/엔트리/2019/03/12/021106
  • 좋은 웹페이지 즐겨찾기