web-dev-qa-db-ja.com

opencv-pythonで透明マスクを作成する方法

背景が白の看板(任意の形の看板)の画像があり、背景が透明な看板の画像を取得したい。

なんとかマスクを作成して画像に適用し、マスクを透明にすることは可能だと思いました。私はここや他の場所でたくさん検索しましたが、何も本当に役に立ちませんでした。

import cv2
import numpy as np

file_name = "/path/to/input/img/Unbenannt.jpg" # can be also .png

img = cv2.imread(file_name)

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
th, threshed = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
morphed = cv2.morphologyEx(threshed, cv2.MORPH_CLOSE, kernel)

_, roi, _ = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

mask = np.zeros(img.shape, img.dtype)

cv2.fillPoly(mask, roi, (255,)*img.shape[2], )

masked_image = cv2.bitwise_and(img, mask)

cv2.imwrite("/path/to/output/mask_test.png", masked_image)

入力:

enter image description here

電流出力:

enter image description here

すでに述べたように、私は背景を透明にしたいです。

ヘルプは大歓迎です。

4
Moritz

背景を透明にするには、画像をBGRAに変換する必要があることがわかりました。また、画像をその境界の長方形にカットするメソッドを追加しました。約束通り、作業コードは次のとおりです。

import cv2
import numpy as np

file_name = "/path/to/img.png"

def cut(img):
  # crop image
  gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  th, threshed = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)

  kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
  morphed = cv2.morphologyEx(threshed, cv2.MORPH_CLOSE, kernel)

  _, cnts, _ = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  cnt = sorted(cnts, key=cv2.contourArea)[-1]
  x,y,w,h = cv2.boundingRect(cnt)
  new_img = img[y:y+h, x:x+w]

  return new_img        

def transBg(img):   
  gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  th, threshed = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)

  kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
  morphed = cv2.morphologyEx(threshed, cv2.MORPH_CLOSE, kernel)

  _, roi, _ = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

  mask = np.zeros(img.shape, img.dtype)

  cv2.fillPoly(mask, roi, (255,)*img.shape[2], )

  masked_image = cv2.bitwise_and(img, mask)

  return masked_image

def fourChannels(img):
  height, width, channels = img.shape
  if channels < 4:
    new_img = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
    return new_img

  return img

s_img = cv2.imread(file_name, -1)

# set to 4 channels
s_img = fourChannels(s_img)

# remove white background
s_img = cut(s_img)

# set background transparent
s_img = transBg(s_img)

cv2.imwrite("/path/to/store/img.png", s_img)

入力は次のとおりです。

enter image description here

出力は、背景が透明な画像です。

enter image description here

2
Moritz