I'm trying to recolor (switch colors) in a photo with Python (preferably Python 3). I have a lot of geometrical shapes that have a thin black border, white fill, and a transparent background.
Here is an example input photo.
I would like to be able to generate a randomly colored circle.
I started with this code:
start_color = (0,0,0) # white
new_color = (255,255,255) # black
# Open image
shape_img = Image.open('circle_example.png').convert('RGB')
shape_data = np.array(shape_img)
# Replace start color with new color
shape_data[(shape_data == start_color).all(axis = -1)] = new_color
# Convert back to image
final_image = Image.fromarray(shape_data, mode='RGB')
final_image.show()
This results in:
Is there a way to replace just the white forefront and not the transparent background? (I realize that the transparent background appears white in this question, but if you look at the picture, it is transparent around the circle.)
I did find an answer. I need to import the alpha levels as well.
import numpy as np
from PIL import Image
start_color = (0, 0, 0, 255) # white
new_color = (255, 255, 255, 255) # black
# Open image
shape_img = Image.open('circle_example.png').convert('RGBA')
shape_data = np.array(shape_img)
# Replace start color with new color
shape_data[(shape_data == start_color).all(axis = -1)] = new_color
# Convert back to image
final_image = Image.fromarray(shape_data, mode='RGBA')
final_image.show()
Related
I have a transparent background image and i want to color all transparent region as black and rest of region as white.
imgage = cv2.imread("imgage.png", cv2.IMREAD_UNCHANGED)
trans_mask = image[:,:,3] == 255
image[trans_mask] = [255, 255, 255, 255]
The output i got it. I got inside area to fill white and outside area to fill black. Any suggestion
Original input
The simplest way to do this is starting out with a fully-black image and filling in just the area with positive alpha:
res = np.zeros(image.shape[:2], np.uint8) # black by default
colored_areas = image[...,3] > 0
res[colored_areas] = 255
You say:
i want to color all transparent region as black and rest of region as white.
So this should satisfy your request:
and you get that from this simple code:
image[:,:,3]
Just apply imwrite or imshow+waitKey (or matplotlib) to see the data.
I found a solution to this but the background is not transparent, it's black and I don't know how I should make it transparent.
Here's my code:
from PIL import Image
image = Image.open('pic.jpg')
image.show()
image_data = image.load()
height,width = image.size
for loop1 in range(height):
for loop2 in range(width):
r,g,b = image_data[loop1,loop2]
image_data[loop1,loop2] = r,0,b
image.save('changed.png')
If your background consists of one color, then you can replace it with transparent in the following way:
from PIL import Image
img = Image.open('pic.png')
rgba = img.convert('RGBA')
data = rgba.getdata()
green_rgb = (0, 128, 0) # change it to your exact bg color
new_data = [item if item[:-1] != green_rgb else (255, 255, 255, 0) for item in data]
rgba.putdata(new_data)
rgba.save('changed.png', 'PNG')
However, if your background is of different shades, then you will have to write additional checks and determine the boundaries of acceptable shades of green.
I want to change image background to black color. I tried with some codes but it didn't work, sometime it removes the object. The backgrounds in this images may vary depends on the places. with curiosity do I need to make machine learning to remove background for this kind of images for better results?
import numpy as np
import cv2
image = cv2.imread(r'D:/IMG_6334.JPG')
r = 150.0 / image.shape[1]
dim = (150, int(image.shape[0] * r))
resized = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
lower_white = np.array([80, 1, 1],np.uint8) #lower hsv value
upper_white = np.array([130, 255, 255],np.uint8) #upper hsv value
hsv_img = cv2.cvtColor(resized,cv2.COLOR_BGR2HSV) #rgb to hsv color space
#filter the background pixels
frame_threshed = cv2.inRange(hsv_img, lower_white, upper_white)
kernel = np.ones((5,5),np.uint8)
#dilate the resultant image to remove noises in the background
#Number of iterations and kernal size will depend on the backgound noises size
dilation = cv2.dilate(frame_threshed,kernel,iterations = 2)
resized[dilation==255] = (0,0,0) #convert background pixels to black color
cv2.imshow('res', resized)
cv2.waitKey(0)
This is a seperate topic on itself. Image matting is the thing you are looking for. This is used to convert your background to black and your foreground to white(which in this case you dont have to do). Check out this website http://alphamatting.com/ where all the state of the art matting algos are present and try implementing it in ur code. I would say this is really long route, so I can say better solution if you mention what exactly are you planning to do after removing the backgrounds of the image.
I've got a color jpg-image of a lion. I've drawn a white circle on the image, converted this image to greyscale and defined a mask. In the end, I want to have an image with only the original pixels within the white circle. I think I'm almost there, but I can't seem to figure out the last step to put all values outside the mask/white circle to black. Here is my code:
import cv2
img = cv2.imread('lion_original.jpg')
center_coordinates = (120,50)
radius = 20
color = (255, 255 , 255)
thickness = -1
img = cv2.circle(img, center_coordinates, radius, color, thickness)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow('try_mask', gray)
mask = gray>254
What you're doing, that is, adding the white circle to the original image, converting that to grayscale and then thresholding is a bad idea: there might be pixels outside of that circle that have values greater than your threshold, and then they will also be included in the mask itself. A quick fix is to create the white circle on a black image. The following snippet gives results that I think correspond to what you need:
img = cv2.imread('A.jpg')
center= (120,50)
radius = 20
color = (255, 255 , 255)
thickness = -1
final_image = cv2.circle(np.zeros_like(img), center, radius, color, thickness).astype("uint8")
final_image[final_image!=0]=img[final_image!=0]
Note: in case there are issues when you visualize final_image, try normalizing it with
final_image=cv2.normalize(src=final_image, dst=None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
before calling cv2.imshow().
When I open a FULLY WHITE file with pillow (from PIL import Image) and then obtain the color of all of the pixels, you SHOULD see something like [255, 255, 255, 255, 255, 255]..... but instead i only see [0, 0, 0, 0, 0, 0]....., code is as follows:
from PIL import Image
image = Image.open("index.png", "r")
pixels = list(image.getdata())
print(pixels)
Your code doesn't convert white pixels values to black pixels. It somehow represents pixel values in different way. We can check whether it converts white pixel values to black pixels using RGB color domain. Code is shown below:
from PIL import Image
import numpy as np
img = Image.open("index.png") # open colour image
imgRgb = img.convert('RGB')
pixels = list(imgRgb.getdata())
width, height = imgRgb.size
pixels = np.asarray([pixels[i * width:(i + 1) * width] for i in range(height)], dtype=int)