Im trying to insert one picture(transparent .png) into another on certain coordinates.
While the solution from How to add an image over another image using x,y coordinates?
frame[y: y+insert_size[1], x: x+insert_size[0]] = image
(where insert_size - width and height of inserted picture) works, i also dont want black pixels(thats how opencv represents transparent pixels) on the final image.
I wrote a function that iterates pixel by pixel, and while it works - it is horribly slow(it completes about 2 image inserts per second), code:
def insert_image(frame, image, insert_coordinates, masked_value):
img_height = len(image)
img_width = len(image[0])
mask = np.ndarray((3,), np.uint8, buffer=np.array(masked_value))
y_diff = 0 #current vertical position in insert picture
for y, line in enumerate(frame):
if y_diff == img_height-1:
continue #interested until last row
if y < insert_coordinates[1] or y > insert_coordinates[1]+img_height:
continue #interested only in rows that will be changed
else:
x_diff = 0 #current horizontal position in insert picture
for x, col in enumerate(line):
if x_diff == img_width-1:
continue #interested until last column
if x < insert_coordinates[0] or x > insert_coordinates[0]+img_width:
continue #interested only in columns that will be changed
else:
if (image[y_diff][x_diff] != mask).all():
frame[y][x] = image[y_diff][x_diff] #setting pixel value if its not of masked value
x_diff += 1
y_diff += 1
return frame
maybe there is a smarter way to do so? opencv version 4.5.0 numpy version 1.20.0rc1
UPDATE: By "insert" i do mean assign a pixel value from image to some pixel of frame. i added data and code for reproducible example(also modified function so its a bit faster):
- "frame" - original picture, that image will be added to to, has red square sized (500,500) at (100,100) coordinates
- "image" - transparent .png, sized (500,500) that will be "inserted" into original frame
- "result1" - result, where red pixels were replaced with black "transparent" pixels from inserted image
- "result2" - desired result
code, requires opencv-python and numpy modules: example.py
import cv2
import numpy as np
import copy
def insert_image_v2(frame, image, insert_coordinates, masked_value):
img_height = len(image)
img_width = len(image[0])
mask = np.ndarray((3,), np.uint8, buffer=np.array(masked_value))
y_diff = 0
for y in range(insert_coordinates[1], insert_coordinates[1]+img_height, 1):
x_diff = 0
for x in range(insert_coordinates[0], insert_coordinates[0]+img_width, 1):
if (image[y_diff][x_diff] != mask).all():
frame[y][x] = image[y_diff][x_diff]
x_diff += 1
y_diff += 1
return frame
if __name__ == "__main__":
frame = cv2.imread('frame.png')
image = cv2.imread('image.png')
insert_size = (image.shape[0], image.shape[1])
insert_coordinates = (100, 100)
x = insert_coordinates[0]
y = insert_coordinates[1]
result1 = copy.deepcopy(frame)
result1[y: y+insert_size[1], x: x+insert_size[0]] = image
result2 = insert_image_v2(frame, image, insert_coordinates, [0,0,0])
cv2.imshow('result1', result1)
cv2.imshow('result2', result2)
cv2.imwrite('result1.jpg', result1)
cv2.imwrite('result2.jpg', result2)
print()