OpenCV: расширение источника видеопотока .png не обеспечивает прозрачность, как ожидалось - PullRequest
0 голосов
/ 19 февраля 2020

Я пытаюсь создать свою собственную программу дополненной реальности с фильтрацией лиц в open-cv. Идея в том, что он отобразит бобра на лицо пользователя. В настоящее время я не могу получить правильную прозрачность при загрузке этого изображения с помощью 'cv2.imread (...)'. Он выглядит черным на заднем плане и часто отображается частично в определенных областях, которые являются белыми Когда я открываю это изображение в фотошопе, я полностью могу переместить это изображение поверх фона с ожидаемыми результатами прозрачности. Мне интересно, если альфа не отображается должным образом. Вот соответствующий код, в который я загружаю изображение.

import numpy
import cv2

def augment_stream(face: numpy.array, augment: numpy.array) -> numpy.array:
    face_h, face_w, _ = face.shape
    augment_h, augment_w, _ = augment.shape

    scalar = min(face_h / augment_h, face_w / augment_w)
    delta_augment_h = int(scalar * augment_h)
    delta_augment_w = int(scalar * augment_w)

    delta_augment_shape = (delta_augment_w, delta_augment_h)
    resized_augment = cv2.resize(augment, delta_augment_shape)

    augmented_face = face.copy()
    dark_pixels = (resized_augment < 250).all(axis=2)
    offset_x = int((face_w - delta_augment_w) / 2)
    offset_y = int((face_h - delta_augment_h) / 2)

    augmented_face[offset_y: offset_y+delta_augment_h, offset_x: offset_x+delta_augment_w][dark_pixels] = resized_augment[dark_pixels]

    return augmented_face

def main():
    stream = cv2.VideoCapture(0)
    cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
    augment = cv2.imread('assets/normal.png')
    # tmp = cv2.cvtColor(augment, cv2.COLOR_BGR2GRAY)
    # _,alpha = cv2.threshold(tmp,0,255,cv2.THRESH_BINARY)
    # b, g, r = cv2.split(augment)
    # rgba = [b,g,r, alpha]
    # dst = cv2.merge(rgba,4)
    # cv2.imwrite("assets/normal.png", dst)


    while True:
        ret, border = stream.read()
        border_h, border_w, _ = border.shape

        bw = cv2.equalizeHist(cv2.cvtColor(border, cv2.COLOR_BGR2GRAY))

        rects = cascade.detectMultiScale(bw, scaleFactor=1.3, minNeighbors=4, minSize=(30, 30), flags=cv2.CASCADE_SCALE_IMAGE)

        for x, y, w, h in rects:
            y0 = int(y - 0.25*h)
            y1 = int(y + 0.75*h)
            x0 = x
            x1 = x + w

            if x0 < 0 or x1 > border_w or y0 < 0 or y1 > border_h:
                continue

            border[y0: y1, x0: x1] = augment_stream(border[y0: y1, x0: x1], augment)

        cv2.imshow('border', border)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    stream.release()
    cv2.destroyAllWindows()


if __name__ == '__main__':
    main()

Augmented Beaver Face

1 Ответ

1 голос
/ 19 февраля 2020

Используя пример из вопроса наложение меньшего изображения на большое изображение python OpenCv

Я уменьшил его, чтобы показать только, как поместить изображение

  • используйте cv2.IMREAD_UNCHANGED, чтобы загрузить его как RGBA.
  • разделите его на RGB и A
  • используйте A для создания масок для image и border
  • используйте l oop для добавления каналы

enter image description here

import cv2

stream = cv2.VideoCapture(0)

# load RGBA
augment = cv2.imread('image.png', cv2.IMREAD_UNCHANGED) # load RGBA

# make it smaller then frame - only for test
W = 320
H = 240
augment = cv2.resize(augment, (W, H))

# split image and alpha
image   = augment[:,:,0:3]
alpha   = augment[:,:,3]
mask_image  = alpha / 255.0
mask_border = 1.0 - mask_image

# ROI - region of interest
x1 = 200
y1 = 100
x2 = x1 + W
y2 = y1 + H

while True:
    ret, border = stream.read()

    # copy only in some region (ROI) (don't assign to variable) but gives worse result
    #cv2.copyTo(image, alpha, border[y1:y2, x1:x2]) 

    for c in range(0, 3): # channels RGB
        border[y1:y2, x1:x2, c] = (image[:, :, c]*mask_image + border[y1:y2, x1:x2, c]*mask_border)

    cv2.imshow('border', border)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

stream.release()
cv2.destroyAllWindows()

Кстати: Я пытался использовать cv2.copyTo(image, mask_image, border), но это дает хуже результат - возможно, для mask / alpha нужно 3 канала.

Кажется, это можно сделать в C / C ++ - , как вставить изображение небольшого размера в большое изображение

...