Remove white background from image with opencv python - python

I have been trying to remove background from a logo and use it as a watermark on product images.I tried to remove background from logo with masking but it also removing black fonts from logo. i need help in removing background without changing the logo. images are attached below. output image is the image i get as output with this code.
logo image: https://drive.google.com/file/d/1yMG6cDuPt8q3EqOJ4Amzp_czWq5hrGS5/view?usp=sharing
product image: https://drive.google.com/file/d/13SmkTgBtWD3yIJq-qGI0aZJ-hjaLbyuB/view?usp=sharing
output image: https://drive.google.com/file/d/1k-fQ9tPUEJKQXPdmdB2ajtliAAG4irNs/view?usp=sharing
this is my code
import cv2
import numpy as np
img = cv2.imread('images/1L2Z3A443AAMC.jpg')
logo = cv2.imread('water2.png')
logo = cv2.resize(logo,(int(img.shape[0]/1.2),int(img.shape[1]/2)))
logo_gray = cv2.cvtColor(logo,cv2.COLOR_BGR2GRAY)
ret,mask= cv2.threshold(logo_gray,245,255,cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
logo_final = cv2.bitwise_and(logo,logo, mask=mask_inv)
h_img,w_img,_ = img.shape
h_logo,w_logo,_ = logo.shape
center_y = int(h_img/2)
center_x = int(w_img/2)
top_y = center_y - (int(h_logo/2))
left_x = center_x - (int(w_logo/2))
bottom_y = top_y + h_logo
right_x = left_x + w_logo
roi = img[top_y:bottom_y,left_x:right_x]
result = cv2.addWeighted(roi,1,logo_final,1,0)
img[top_y:bottom_y,left_x:right_x] = result
cv2.imwrite('sample.jpg',img)

In order to remove the background from a logo. We need to used masking. A masking for the foreground and another masking for the background.
logo = cv2.imread("water2.png", -1)
logo_mask = logo[:,:,3]
logo_mask_inv = cv2.bitwise_not(logo_mask)
logo = logo[:,:,0:3]
logo_background = cv2.bitwise_and(roi, roi, mask=logo_mask_inv)
logo_foreground = cv2.bitwise_and(logo, logo, mask=logo_mask)
final_logo = cv2.add(logo_background, logo_foreground)

Related

How to better crop and paste an image in PIL

I am trying to crop an avatar and place it in a given location in another image using python pil.
Here is the output of what I have so far:
And here is the code:
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
import textwrap
text = "Creating Twitter Cards dynamically with Python"
background_image = "data/obi-pvc.png" # this is the background
avatar = Image.open("data/avatar.png")
font = "data/fonts/AllertaStencil-Regular.ttf"
background = Image.open(background_image)
background_width, background_height = background.size
avatar.convert('RGBA')
## DO NOT change below this line!!
save_name = f"{text.lower().replace(' ', '_')}.png"
#textwrapped = textwrap.wrap(text, width=text_wrap_width)
# crop avatar
width, height = avatar.size
x = (width - height)//2
avatar_cropped = avatar.crop((x, 0, x+height, height))
width_cr, height_cr = avatar_cropped.size
# create grayscale image with white circle (255) on black background (0)
mask = Image.new('L', avatar_cropped.size)
mask_draw = ImageDraw.Draw(mask)
width, height = avatar_cropped.size
mask_draw.ellipse((0, 0, width, height), fill=255)
# add mask as alpha channel
avatar_cropped.putalpha(mask)
draw = ImageDraw.Draw(background)
font = ImageFont.truetype(font, font_size)
draw.text((offset,margin), '\n'.join(textwrapped), font=font, fill=color)
x, y = avatar_cropped.size
margin = 40
# left top
position_tl = (0 + margin, 0 + margin)
position_tr = (x - margin - width_cr, 0 + margin)
position_bl = (0 + margin, y - margin - height_cr)
position_br = (x - margin - width_cr, y - margin - height_cr)
background.paste(avatar_cropped, position)
background.save(f"data/output/{save_name}")
display(background)
The avatar should fit within the circle. I can't seem to really figure out how to apply the positioning. Thanks
Here is the avatar:

How to add a text in the captured image

I have created a app which capture the image and convert into pencil sketch.
I need to add a watermark inside the capture image I find for the documentation I didn't get the exact one let me know how to add a water mark inside the image or any idea would be appreciated.
import base64
import streamlit as st
import numpy as np
from PIL import Image
import cv2
def dodgeV2(x, y):
return cv2.divide(x, 255 - y, scale=256)
def pencilsketch(inp_img):
img_gray = cv2.cvtColor(inp_img, cv2.COLOR_BGR2GRAY)
img_invert = cv2.bitwise_not(img_gray)
img_smoothing = cv2.GaussianBlur(img_invert, (21, 21),sigmaX=0, sigmaY=0)
final_img = dodgeV2(img_gray, img_smoothing)
logo_img = cv2.imread("Watertext.jpg")
logo_gray = cv2.cvtColor(logo_img, cv2.COLOR_BGR2GRAY)
logo_height, logo_width = logo_gray.shape[:2]
#y_offset = x_offset = 0 # paste to the top left of image
x_offset = final_img.shape[1] - logo_width
y_offset = 0
final_img[x_offset:x_offset+logo_height, y_offset:y_offset+logo_width] = logo_gray
return(final_img)
Modify your pencilsketch function like
def pencilsketch(inp_img):
img_gray = cv2.cvtColor(inp_img, cv2.COLOR_BGR2GRAY)
img_invert = cv2.bitwise_not(img_gray)
img_smoothing = cv2.GaussianBlur(img_invert, (21, 21),sigmaX=0, sigmaY=0)
final_img = dodgeV2(img_gray, img_smoothing)
logo_img = cv2.imread("path/to/logo/image.jpg")
logo_gray = cv2.cvtColor(logo_img, cv2.COLOR_BGR2GRAY)
logo_height, logo_width = logo_gray.shape[:2]
x_offset = y_offset = 0 # paste to the top left of image
final_img[y_offset:y_offset+logo_height, x_offset:x_offset+logo_width] = logo_gray
return(final_img)
If you want to paste in top right, change line
x_offset = y_offset = 0 # paste to the top left of image
to
x_offset = final_img.shape[1] - logo_width
y_offset = 0
If you want to paste in bottom right, change line
x_offset = y_offset = 0 # paste to the top left of image
to
x_offset = final_img.shape[1] - logo_width
y_offset = final_img.shape[0] - logo_height
Make use of cv2.addWeighted() which is used to blend images.
This is an example:
output_img = cv2.addWeighted(input_img, 1, watermark, 0.5, 0)
using OpenCV you can add a watermark on your photos and video also, you need to import the library and use it.
**import cv2
img = cv2.imread('diego-jimenez-A-NVHPka9Rk-unsplash.JPG')
watermark = cv2.imread("Watermark.JPG")**
for more references go to this blog post

PIL: Paste image with resized aspect ratio

I have 2 images (icon.png and background.png). In the background.png image, there is a blank area which will be the place for the icon.png to be pasted using PIL (Python). However, the icon.png is a little bit bigger compared to the blank frame in the background.png. How can I paste and make the icon.png smaller so it can fit with the frame?
My code so far:
icon = Image.open("./icon.png")
background = Image.open("./background.png")
mask = Image.new("L", icon.size, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0) + icon.size, fill=255)
back_im = background.copy()
back_im.paste(icon, (200, 100), mask=mask)
back_im.save("./back_im.png")
Use resize after read the icon image to fit the desired size:
from PIL import Image, ImageDraw
iconSize=(200,100)
icon = Image.open("./icon.png")
icon=icon.resize(iconSize)
background = Image.open("./background.png")
mask = Image.new("L", icon.size, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0) + icon.size, fill=255)
back_im = background.copy()
# back_im.paste(icon, iconSize, mask=mask)
back_im.paste(icon, icon.size, mask=mask)
back_im.save("./back_im.png")

OpenCV is too slow for this

I want to overlay webcam captured video on another video in live. So I have tried the above code,but it's too slow.
Should I shift to another language or lib or something?
Any suggestion or help will be appreciated.
import numpy as np
from cv2 import cv2
def image_resize(image, width = None, height = None, inter = cv2.INTER_AREA):
# initialize the dimensions of the image to be resized and
# grab the image size
dim = None
(h, w) = image.shape[:2]
# if both the width and height are None, then return the
# original image
if width is None and height is None:
return image
# check to see if the width is None
if width is None:
# calculate the ratio of the height and construct the
# dimensions
r = height / float(h)
dim = (int(w * r), height)
# otherwise, the height is None
else:
# calculate the ratio of the width and construct the
# dimensions
r = width / float(w)
dim = (width, int(h * r))
# resize the image
resized = cv2.resize(image, dim, interpolation = inter)
# return the resized image
return resized
cap2 = cv2.VideoCapture('http://192.168.43.1:8080/video')
cap = cv2.VideoCapture('test.mp4')
# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('sample3.mp4',fourcc,30, (640,480))
# watermark = logo
# cv2.imshow("watermark",watermark)
while(cap.isOpened()):
ret, frame = cap.read()
frame = cv2.cvtColor(frame,cv2.COLOR_BGR2BGRA)
ret2 ,frame2 = cap2.read()
frame2 = cv2.cvtColor(frame2,cv2.COLOR_BGR2BGRA)
watermark = image_resize(frame2,height=177)
if ret==True:
frame_h, frame_w, frame_c = frame.shape
overlay = np.zeros((frame_h, frame_w, 4), dtype='uint8')
overlay[543:543+177,1044:1044+236] = watermark
cv2.addWeighted(frame, 0.25, overlay, 1.0, 0, frame)
frame = cv2.cvtColor(frame,cv2.COLOR_BGRA2BGR)
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()
Requirement is to overlay webcam live video on another video at bottom smoothly.
Thanks.
Basically, if you want it to be fast, you may not iterate over an image using a python cycle. You are trying to copy the scaled-down image into the empty overlay using 2 nested cycles and that's terribly slow. I do not understand the condition
if watermark[i,j][3] != 0:
Also this part:
offset = 0
h_offset = frame_h - watermark_h -offset
w_offset = frame_w - watermark_w - offset
should be out of the cycle - they are all constants.
But most importantly instead of cycling over the image you can do:
offset[h_offset:h_offset+watermark_h,w_offset:w_offset+watermark_w] = watermark
After this, I am up from 9 fps to 28 fps.

PIL image rotation and background issue

I am trying to rotate my transparent gif using the PIL rotate() but I am getting a diamond after rotating it.
Similar problems on SO were solved by using
transparency = img.info['transparency']
img.save('result.gif',transparency=transparency)
or by using
img.save('result.gif', **img.info)
But I am getting the following results as in the images.
My code is
from PIL import Image
file = 'change2_1.gif'
with Image.open(file) as im:
transparency = im.info['transparency']
img = im.rotate(45, expand=True)
img.save('result.gif', transparency=transparency)
Post edited: Try to use this to make black backgroud transparent
from PIL import Image
img = Image.open('img.png')
img = img.convert("RGBA")
datas = img.getdata()
with Image.open(file) as im:
transparency = im.info['transparency']
img = im.rotate(90, expand=True)
img.save('result.gif', transparency=transparency)
newData = []
for item in datas:
if item[0] == 0 and item[1] == 0 and item[2] == 0:
newData.append((255, 255, 255, 0))
else:
newData.append(item)
To avoid having a black frame after rotation, simply change the default mode ('RGB') to 'RGBA' after opening :
img = Image.open('image.png').convert('RGBA')
img.rotate(90, expand = True)

Categories