Наложение меньшего изображения на большее изображение python OpenCv
Привет, Я создаю программу, которая заменяет лицо в изображении лицом другого лица. Тем не менее, я застрял в попытке вставить новое лицо в оригинальное более крупное изображение. Я исследовал ROI и addWeight (требуется, чтобы изображения были одного размера), но я не нашел способ сделать это в python. Любые советы велики. Я новичок в opencv.
Я использую следующие тестовые изображения:
smaller_image:
![enter image description here]()
larger_image:
![enter image description here]()
Вот мой код до сих пор... микшер других образцов:
import cv2
import cv2.cv as cv
import sys
import numpy
def detect(img, cascade):
rects = cascade.detectMultiScale(img, scaleFactor=1.1, minNeighbors=3, minSize=(10, 10), flags = cv.CV_HAAR_SCALE_IMAGE)
if len(rects) == 0:
return []
rects[:,2:] += rects[:,:2]
return rects
def draw_rects(img, rects, color):
for x1, y1, x2, y2 in rects:
cv2.rectangle(img, (x1, y1), (x2, y2), color, 2)
if __name__ == '__main__':
if len(sys.argv) != 2: ## Check for error in usage syntax
print "Usage : python faces.py <image_file>"
else:
img = cv2.imread(sys.argv[1],cv2.CV_LOAD_IMAGE_COLOR) ## Read image file
if (img == None):
print "Could not open or find the image"
else:
cascade = cv2.CascadeClassifier("haarcascade_frontalface_alt.xml")
gray = cv2.cvtColor(img, cv.CV_BGR2GRAY)
gray = cv2.equalizeHist(gray)
rects = detect(gray, cascade)
## Extract face coordinates
x1 = rects[0][3]
y1 = rects[0][0]
x2 = rects[0][4]
y2 = rects[0][5]
y=y2-y1
x=x2-x1
## Extract face ROI
faceROI = gray[x1:x2, y1:y2]
## Show face ROI
cv2.imshow('Display face ROI', faceROI)
small = cv2.imread("average_face.png",cv2.CV_LOAD_IMAGE_COLOR)
print "here"
small=cv2.resize(small, (x, y))
cv2.namedWindow('Display image') ## create window for display
cv2.imshow('Display image', small) ## Show image in the window
print "size of image: ", img.shape ## print size of image
cv2.waitKey(1000)
Ответы
Ответ 1
Простой способ достичь желаемого:
import cv2
s_img = cv2.imread("smaller_image.png")
l_img = cv2.imread("larger_image.jpg")
x_offset=y_offset=50
l_img[y_offset:y_offset+s_img.shape[0], x_offset:x_offset+s_img.shape[1]] = s_img
![the result image]()
Update
Полагаю, вы тоже захотите позаботиться об альфа-канале. Вот быстрый и грязный способ сделать это:
s_img = cv2.imread("smaller_image.png", -1)
y1, y2 = y_offset, y_offset + s_img.shape[0]
x1, x2 = x_offset, x_offset + s_img.shape[1]
alpha_s = s_img[:, :, 3] / 255.0
alpha_l = 1.0 - alpha_s
for c in range(0, 3):
l_img[y1:y2, x1:x2, c] = (alpha_s * s_img[:, :, c] +
alpha_l * l_img[y1:y2, x1:x2, c])
![result image with alpha]()
Ответ 2
Основываясь на превосходном ответе огненного выше, вот альфа-смешивание, но немного более понятное для человека. Возможно, вам придется поменять местами 1.0-alpha
и alpha
в зависимости от того, в каком направлении вы сходите (мой поменялся от ответа на автоответчик).
o* == s_img.*
b* == b_img.*
for c in range(0,3):
alpha = s_img[oy:oy+height, ox:ox+width, 3] / 255.0
color = s_img[oy:oy+height, ox:ox+width, c] * (1.0-alpha)
beta = l_img[by:by+height, bx:bx+width, c] * (alpha)
l_img[by:by+height, bx:bx+width, c] = color + beta
Ответ 3
Используя @fireant идею, я написал функцию для обработки наложений. Это хорошо работает для любого аргумента позиции (включая отрицательные позиции).
def overlay_image_alpha(img, img_overlay, pos, alpha_mask):
"""Overlay img_overlay on top of img at the position specified by
pos and blend using alpha_mask.
Alpha mask must contain values within the range [0, 1] and be the
same size as img_overlay.
"""
x, y = pos
# Image ranges
y1, y2 = max(0, y), min(img.shape[0], y + img_overlay.shape[0])
x1, x2 = max(0, x), min(img.shape[1], x + img_overlay.shape[1])
# Overlay ranges
y1o, y2o = max(0, -y), min(img_overlay.shape[0], img.shape[0] - y)
x1o, x2o = max(0, -x), min(img_overlay.shape[1], img.shape[1] - x)
# Exit if nothing to do
if y1 >= y2 or x1 >= x2 or y1o >= y2o or x1o >= x2o:
return
channels = img.shape[2]
alpha = alpha_mask[y1o:y2o, x1o:x2o]
alpha_inv = 1.0 - alpha
for c in range(channels):
img[y1:y2, x1:x2, c] = (alpha * img_overlay[y1o:y2o, x1o:x2o, c] +
alpha_inv * img[y1:y2, x1:x2, c])
Использование:
overlay_image_alpha(img_large,
img_small[:, :, 0:3],
(x, y),
img_small[:, :, 3] / 255.0)
Ответ 4
Если кто-то, как я, получает ошибку:
ValueError: назначение назначения доступно только для чтения
при попытке записи в целевое изображение, используя любой из этих ответов выше.
Быстрое исправление состоит в том, чтобы установить флаг WRITEABLE в true:
img.setflags(write=1)
Ответ 5
Просто добавьте альфа-канал в s_img. Я просто использую cv2.addWeighted перед строкой l_img[y_offset:y_offset+s_img.shape[0], x_offset:x_offset+s_img.shape[1]] = s_img
следующим образом:
s_img=cv2.addWeighted(l_img[y_offset:y_offset+s_img.shape[0], x_offset:x_offset+s_img.shape[1]],0.5,s_img,0.5,0)
Ответ 6
Вот:
def put4ChannelImageOn4ChannelImage(back, fore, x, y):
rows, cols, channels = fore.shape
trans_indices = fore[...,3] != 0 # Where not transparent
overlay_copy = back[y:y+rows, x:x+cols]
overlay_copy[trans_indices] = fore[trans_indices]
back[y:y+rows, x:x+cols] = overlay_copy
#test
background = np.zeros((1000, 1000, 4), np.uint8)
background[:] = (127, 127, 127, 1)
overlay = cv2.imread('imagee.png', cv2.IMREAD_UNCHANGED)
put4ChannelImageOn4ChannelImage(background, overlay, 5, 5)