By kaboomfox


2012-12-28 00:26:20 8 Comments

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.

I am using the following test images:

smaller_image:

enter image description here

larger_image:

enter image description here

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)              

6 comments

@Nadav B 2018-10-10 14:29:26

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)

@guilhermeh2m 2018-10-05 13:26:19

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

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)

@Torantula 2018-02-17 19:49:11

If anyone, like me, gets the error:

ValueError: assignment destination is read-only

when attempting to write to the destination image using any of these answers above.

A quick dirty fix is to set the WRITEABLE flag to true:

img.setflags(write=1)

@Mateen Ulhaq 2017-07-15 12:06:35

Using @fireant's idea, I wrote up a function to handle overlays. This works well for any position argument (including negative positions).

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)

@Schütze 2018-08-08 01:44:34

IndexError: index 3 is out of bounds for axis 2 with size 3 is the error one gets with this.

@Alok Subedi 2018-08-09 08:37:31

how do i overlay the larger image's centroid with the smaller image's centroid? I have the centroids of both the images already. I used the function above, but the smaller image's leftmost pixel is automatically overlayed on the larger image.

@fireant 2012-12-31 13:07:58

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

the result image

Update

I suppose you want to take care of the alpha channel too. Here is a quick and dirty way of doing so:

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

@Jonathan Crowe 2016-06-25 17:54:24

I know this is an ancient question but would you mind adding an explanation of what is going on in the alpha channel example? I'm getting into cv2 and python and this stuff is still a huge question mark for me

@Adib 2016-06-30 05:56:12

Seconding Jonathan's request. I want to know what the math is doing so I can better debug the problem

@fireant 2016-07-14 18:58:42

@JonathanCrowe to overlay image1 over imag2, [result-image::rgb channel] = [image1::rgb-channel] * [imag1::alpha-channel] + [image2::rgb-channel] * (1.0-[imag1::alpha-channel]).

@fireant 2016-07-14 18:58:57

@Adib see the above comment

@GuySoft 2016-08-03 14:22:03

Hey, in the update your line is cut: l_img[y_offset:y_offset+s_img.shape[0], x_offset:x_offset+s_img.shape[1], c] = What did you mean there?

@Olezt 2017-03-29 16:39:33

It is not cut. The rest is on the next line. Works perfect. :) @GuySoft

@Kurt 2016-11-20 20:32:16

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-alpha and alpha depending on which direction you're merging (mine is swapped from fireant's answer).

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

Related Questions

Sponsored Content

24 Answered Questions

28 Answered Questions

[SOLVED] Finding the index of an item given a list containing it in Python

  • 2008-10-07 01:39:38
  • Eugene M
  • 2934905 View
  • 2433 Score
  • 28 Answer
  • Tags:   python list

15 Answered Questions

[SOLVED] Does Python have a string 'contains' substring method?

31 Answered Questions

[SOLVED] How to get the current time in Python

  • 2009-01-06 04:54:23
  • user46646
  • 2396572 View
  • 2117 Score
  • 31 Answer
  • Tags:   python datetime time

53 Answered Questions

[SOLVED] Calling an external command in Python

25 Answered Questions

[SOLVED] How can I safely create a nested directory in Python?

22 Answered Questions

[SOLVED] What is the difference between @staticmethod and @classmethod?

24 Answered Questions

[SOLVED] Difference between append vs. extend list methods in Python

15 Answered Questions

[SOLVED] What are metaclasses in Python?

1 Answered Questions

[SOLVED] openCV: cannot detect small shapes using findContours

  • 2017-10-08 07:40:30
  • Vic
  • 643 View
  • 1 Score
  • 1 Answer
  • Tags:   python opencv

Sponsored Content