Convert an image to black and white mask using opencv python - python

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.

Related

how to isolate yellow part of the picture and make black other parts?

This is the image:
I want to turn all the colours to black except yellow and tried this code but showing an error can anyone please help?
import cv2 as cv
import numpy as np
img = cv.imread('Screenshot 2022-04-10 at 10.02.19 AM.png',1)
if(img.any() == [255, 255, 0]):
cv.imshow('image',img);
else:
ret , thresh1 = cv.threshold(img,500,255,cv.THRESH_BINARY);
cv.imshow("Timg",thresh1);
cv.waitKey(0)
cv.destroyAllWindows()
The error is showing for the if conditional statement.
The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Steps: TLDR;
Convert image to LAB color space
Otsu Threshold over b-component
Mask the result over the original image in BGR color space
Code
# read the image in BGR
img = cv2.imread("image_path", 1)
# convert image to LAB color space
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
# store b-component
b_component = lab[:,:,2]
# perform Otsu threshold
ret,th = cv2.threshold(b_component, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# mask over original image
result = cv2.bitwise_and(img, img, mask = th)
Details
Why did I do this?
The LAB color space contains 3 channels:
L-component: highlights brightness value
a-component: represents color values between green and magenta
b-component: represents color values between blue and yellow
Since your image comprised of blue, magenta and yellow, I opted for LAB color space. And specifically the b-component because it highlights yellow color

I have an image, how do i change it to pure black and white such that only a specific colour becomes white

Only the coloured stuff stays the same colour, like if I have a dark background, white text but one bit of text is light green #00FF00, how do I change it to a pure black and white image like normal, but only that specific green becomes white?
The name of the image I want to work on is 'download.png'
Here is my current code for reference:
originalImage = cv2.imread('download.png')
grayImage = cv2.cvtColor(originalImage, cv2.COLOR_BGR2GRAY)(thresh, blackAndWhiteImage) = cv2.threshold(grayImage, 80, 255, cv2.THRESH_BINARY)
im = Image.fromarray(blackAndWhiteImage)
im.save('download.png')
The above code just turns the image pure black and white based on a threshold of the brightness of 80/255. I want to replace this threshold with a specific colour (#00FF00)
User fmw42 said I need to use cv2.inRange to threshold on a colour. This works.

Make circular mask and put all values outside of mask to black

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().

How to color parts of an Image Mask with the original target Image color using opencv or PIL?

I need help to create a mask of an image where parts of the image are black due to Masking but some part still retain the original color of the image. Imagine a thug that wears a ski mask where part of the eye and mouth is the thug's skin while the rest of the face are covered with the ski mask.
Basically what I want is the eyebrows, eye and lips part should retain the original image but the rest of the mask stay white like the picture above.
So far by using PIL, I have successfully create a mask and fill out the inside of the "eye" part with black color
def getmask(img,jawline,eyebrows,eyes,mouth):
img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
imArray = np.asarray(img)
# create mask
polygon = jawline.flatten().tolist()
maskIm = Image.new('L', (imArray.shape[1], imArray.shape[0]), 0)
ImageDraw.Draw(maskIm).polygon(polygon, outline=1, fill='white')
#ImageDraw.Draw(maskIm).polygon(polygon, outline=(1))
# draw eyes
righteyes=eyes[0:6].flatten().tolist()
ImageDraw.Draw(maskIm).polygon(righteyes, outline=1,fill='black')
lefteyes=eyes[6:].flatten().tolist()
ImageDraw.Draw(maskIm).polygon(lefteyes, outline=1,fill='black')
mask = np.array(maskIm)
# draw eyebrows
rightbrows=eyebrows[0:6].flatten().tolist()
ImageDraw.Draw(maskIm).polygon(rightbrows, outline=2, fill='black')
leftbrows=eyebrows[6:].flatten().tolist()
ImageDraw.Draw(maskIm).polygon(leftbrows, outline=2, fill='black')
# draw mouth
mouth=mouth.flatten().tolist()
ImageDraw.Draw(maskIm).polygon(mouth, outline=1, fill='black')
mask = np.array(maskIm)
return mask
those jawline, eyebrows, eyes, mouth contains the (x,y) coordinate for the related part of the face and I only need to retain the color on Eyebrows,eyes and mouth part. I hope someone can help me solve it
If you have a mask where by the area's you want to keep are in white then you can simply do a bitwise_or with it on the original image.
In your case we have to invert the mask so that the background is black and the ROI's are white.
mask = cv2.bitwise_not(mask)
masked = cv2.bitwise_or(image, image, mask=mask)
Here is an example of the output:
For the rest of his face to be black you would just set all the values outside of the ROI to black in the mask. One way would be to use the coordinates provided by
np.where(mask != 0)
Example Code:
https://colab.research.google.com/drive/1vCMhgDXmuFMJpxChuLN6TDEqgXi7V8CT

Numpy np.any range or threshold

I am using python, OpenCV and Numpy. My goal is to find all white pixel and turn it red and turn everything else off or white. My code:
import numpy as np
import cv2
import matplotlib.pyplot as plt
# Read mask
image = cv2.imread("path to my image")
any_white = np.any(image == [255,255,255], axis = -1)
image[any_white]=[255,0,0]
plt.imshow(image)
plt.show()
cv2.imwrite('result.png',image)
Problem 1: Targetting any [255,255,255] doesn't find all, whiteist, I starting finding any [244,244,244], [243,243,243] and so on. Is there a way to set a range of white, maybe from [255,255,255] to [230,230,230]?
Problem 2: clearly, with plt.imshow(image) and plt.show() within python, the result shows red, but when i used cv2.imwrite('result.png',image) to save, it's blue. See result image.
Problem 1:
You can create a mask and set the red channel to False so that you keep the value at 255 if you want to target only the white pixels
mask_bg = (image == [255, 255, 255])
mask_bg[:, :, 0] = False # set red channel mask to false (leave 255 value)
image[mask_bg] = 0 # set all white pixels to [255, 0, 0]
If you want to find all values in a range you can use cv2.inRange:
mask = cv2.inRange(image, (230, 230, 230), (255, 255,255))
Problem 2:
OpenCV uses BGR as default instead of RGB, you can convert from BGR to RGB with:
new_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
cv2.imshow('BGR Image', new_image )
Keep in mind that if you open an image with OpenCV it will be BGR, so convert it before manipulating the channels.
Problem 1:
The pixels you are planning to target may not have the exact value of (255, 255, 255). Hence it is better to binarize the image by setting a range of pixel values. You can find the exact range by creating Trackbars and tuning them manually. You can find more about implementing Trackbars in OpenCV here.
Problem 2:
This happens because OpenCV uses BGR or (Blue, Green, Red) colorspace by default. You can change the colorspace into RGB or (Red, Green, Blue) by using cv2.cvtColor(image, cv2.COLOR_BGR2RGB) before saving.

Categories