在较大的图像上覆盖较小的图像 python OpenCv
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14063070/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
overlay a smaller image on a larger image python OpenCv
提问by kaboomfox
Hi I am creating a program that replaces a face in a image with someone else's face. However, I am stuck on trying to insert the new face into the original, larger image. I have researched ROI and addWeight(needs the images to be the same size) but I haven't found a way to do this in python. Any advise is great. I am new to opencv.
嗨,我正在创建一个程序,用其他人的脸替换图像中的脸。但是,我一直在尝试将新面孔插入到原始的较大图像中。我已经研究了 ROI 和 addWeight(需要图像大小相同),但我还没有找到在 python 中执行此操作的方法。任何建议都很棒。我是 opencv 的新手。
I am using the following test images:
我正在使用以下测试图像:
smaller_image:
较小的图像:


larger_image:
更大的图像:


Here is my Code so far... a mixer of other samples:
到目前为止,这是我的代码……其他示例的混合器:
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)
回答by fireant
A simple way to achieve what you want:
实现您想要的简单方法:
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


Update
更新
I suppose you want to take care of the alpha channel too. Here is a quick and dirty way of doing so:
我想你也想处理 alpha 通道。这是一种快速而肮脏的方法:
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])


回答by Kurt
Based on fireant's excellent answer above, here is the alpha blending but a bit more human legible. You may need to swap 1.0-alphaand alphadepending on which direction you're merging (mine is swapped from fireant's answer).
基于上面 fireant 的出色回答,这里是 alpha 混合,但更易读。您可能需要交换1.0-alpha,alpha具体取决于您合并的方向(我的是从消防员的答案中交换的)。
o* == s_img.*b* == b_img.*
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
回答by Mateen Ulhaq
Using @fireant's idea, I wrote up a function to handle overlays. This works well for any position argument (including negative positions).
使用@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])
Usage is:
用法是:
overlay_image_alpha(img_large,
img_small[:, :, 0:3],
(x, y),
img_small[:, :, 3] / 255.0)
回答by Torantula
When attempting to write to the destination image using any of these answers above and you get the following error:
尝试使用上述任何答案写入目标图像时,您会收到以下错误:
ValueError: assignment destination is read-only
A quick potential fix is to set the WRITEABLE flag to true.
一个快速的潜在解决方法是将 WRITEABLE 标志设置为 true。
img.setflags(write=1)
回答by guilhermeh2m
For just add an alpha channel to s_img I just use cv2.addWeighted before the line
l_img[y_offset:y_offset+s_img.shape[0], x_offset:x_offset+s_img.shape[1]] = s_img
对于只向 s_img 添加一个 alpha 通道,我只是在行之前使用 cv2.addWeighted
l_img[y_offset:y_offset+s_img.shape[0], x_offset:x_offset+s_img.shape[1]] = s_img
as following: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)
如下: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)
回答by Nadav B
Here it is:
这里是:
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)

