Adding an alpha channel to a Monochrome Image using Open CV Python - python

I have been working on colour images(RGB) and color images with an alpha channel(RGBA) . Reading an alpha channel from an RGBA image is pretty easy and I can even split the 4 channels of the image. Is there any method by which I can add an alpha channel to a monochrome or a grayscale image? Also, can alpha channel be separately added to the R,G,B Channels individually ?
The code I am using to read a transparent image and split the channels is as follows -
import cv2
img = cv2.imread(image1_path,-1)
b = img[:,:,0]
g = img[:,:,1]
r = img[:,:,2]
a = img[:,:,3]
img_merge = cv2.merge((b,g,r,a))
cv2.imshow("img_merge",img_merge)
cv2.imshow("r channel",r)
cv2.imshow("g channel",g)
cv2.imshow("b channel",b)
cv2.imshow("a channel",a)
cv2.waitKey(0)
cv2.destroyAllWindows()
The image I am using is -

You cannot create a 2-channel "luminance-alpha" image, however you can convert the 1-channel grayscale image to BGRA using only gray values by duplicating the grayscale channel and adding the alpha channel to that. Let l be the grayscale image:
img_3gray = cv2.merge((l,l,l,a))
Nor can you apply an alpha channel to just one channel of an image, but you can take a single channel of the image (say, blue) and turn it into a grayscale image as we did before:
img_3blue = cv2.merge((b,b,b,a))
or you can display only the blue channel with alpha:
img_bzz = cv2.merge((b,z,z,a))
where z is all zeroes.

Related

Python - replicating the GIMP's "Erase color" blend mode

I'm looking for a way to recreate the GIMP's Erase color blending mode in Python 3 & OpenCV2.
I know it's possible to erase color using the that library, but the code I run works on exactly one of them. Furthermore, I don't believe such small amount of code could do that advanced thing.
Looking for a solution, I found the blend-modes by flrs, but it also doesn't include the option I want.
Sadly, I have no experience in OpenCV2 at the moment, but I think developing such thing could be very helpful.
Can someone guide me how to make this more reliable, or is it even possible to do with things that I've got already?
OpenCV2 color removal
Code
import cv2
from PIL import Image
#-=-=-=-#
File_Name = r"Spectrogram.png"
SRC = cv2.imread(File_Name, 1)
TMP = cv2.cvtColor(SRC, cv2.COLOR_BGR2GRAY)
_, A = cv2.threshold(TMP, 0, 255, cv2.THRESH_BINARY)
B, G, R = cv2.split(SRC)
Colors = [B, G, R, A]
Picture = cv2.merge(Colors, 4)
#-=-=-=-#
# My CV2 image display doesn't include transparency
im = cv2.cvtColor(Picture, cv2.COLOR_BGR2RGB)
im = Image.fromarray(im)
im.show()
Result
Original
Result
GIMP Erase color blending-mode
Type
Background
Foreground
Result
Image
Blending
Normal
Erase color
Normal
Here is one simple way in Python/OpenCV.
Read the input
Choose a color range
Apply range to threshold the image
Invert the range as a mask to be used later for the alpha channel
Convert the image from BGR to BGRA
Put mask into the alpha channel of the BGRA image
Save the result
Input:
import cv2
import numpy as np
# load image and set the bounds
img = cv2.imread("red_black.png")
# choose color range
lower =(0,0,0) # lower bound for each BGR channel
upper = (140,0,190) # upper bound for each BRG channel
# create the mask
mask = cv2.inRange(img, lower, upper)
# invert mask
mask = 255 - mask
# convert image to BGRA
result = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
# put mask into alpha channel
result[:,:,3] = mask
# write result to disk
cv2.imwrite("red_black_color_removed.png", result)
# display it (though does not display transparency properly)
cv2.imshow("mask", mask)
cv2.imshow("results", result)
cv2.waitKey(0)
Result:

How delete channel in image opencv

I i have two different images(frames of video):
first image:
print(img1.shape)
(31,27,3)
second image:
print(img2.shape)
(31,27)
How i can delete on first image the value 3?
img1.shape variable returns height, width, channel of your current image.
How i can delete on first image the value 3?
3 refers to BGR channel in your image.
(I assume you read the image using cv2.imread)
You can convert to the gray-scale by
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
Now print(img1.shape)
and result will be:
(31, 27)
The 3 means that you have an RGB image, a color image.
If you want to make it grayscale, as I guess your second image is, use
from skimage import color
gray_image = color.rgb2gray(image)

Unsupported depth of input image: 'VDepth::contains(depth)' where 'depth' is 4 (CV_32S)

I'm trying to process some images in OpenCV. Specifically, swapping color panes using the following functions.
def green_ble_swap(image)
im_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
im_copy = np.copy(im_rgb)
blue = im_copy[:,:,2].copy()
green = im_copy[:,:,1].copy()
im_copy[:,:,2] = green
im_copy[:,:,1] = blue
return im_copy
However I get the following error.
> Unsupported depth of input image:
> 'VDepth::contains(depth)'
> where
> 'depth' is 4 (CV_32S)
Not sure whats the error here.
You're encountering the error because you're trying to perform a 3-channel operation on a 4-channel image. Specifically, the error comes from trying to convert a BGR image to RGB when the input image has a transparent channel. The correct method would be to do cv2.COLOR_BGRA2RGB instead of cv2.COLOR_BGR2RGB. You can swap the blue and green channels in-place using cv2.split() to obtain the BGR channels (for 3-channel image) and BGRA channels for (4-channel image) then swap the channels using Numpy indexing. You also need to use the cv2.IMREAD_UNCHANGED flag when loading the image or the alpha channel will be dropped. Example:
Input -> Output
import cv2
import numpy as np
def green_blue_swap(image):
# 3-channel image (no transparency)
if image.shape[2] == 3:
b,g,r = cv2.split(image)
image[:,:,0] = g
image[:,:,1] = b
# 4-channel image (with transparency)
elif image.shape[2] == 4:
b,g,r,a = cv2.split(image)
image[:,:,0] = g
image[:,:,1] = b
return image
# Load image
image = cv2.imread('1.png', cv2.IMREAD_UNCHANGED)
cv2.imshow('image', image)
# Swap channels
swapped = green_blue_swap(image)
cv2.imshow('swapped', swapped)
cv2.waitKey()

I have converted 3 channel RGB image into 2 channels grayscale image, How to decrease greyscale channels to 1?

I have Converted 3 Channel RGB image into 2 channel grayscale image using :
from PIL import Image
import glob
images = glob.glob('C:/Users/.../*.jpg')
for i in range(len(images)):
img = Image.open(images[i]).convert('LA')
img = img.resize((224,224),Image.ANTIALIAS)
img.save('C:/Users/.../0_{}.png'.format(i))
My Goal was to create 1 channel grayscale but after doing code above, i found out that results are 2 channels images ! is there any way that i can decrease this channels to 1 as if i converted them from 3 to 1 at first place ?
Thanks.
Calling convert with LA gives it two channels, L, which is luminosity, and A, which is alpha (transparency). So if you do Image.open(images[i]).convert('L') there will only be one channel in the resulting image.

How to save an image with more than 3 channels using PIL?

I need to save a tiff image with 4 channels, specifically R,G,B and A channels.
When I try using Image.save() to save a tiff with 4 channels, the resulting image is an RGBA image but when examining the tiff in Photoshop the only channels are RGB, without the Alpha. Is there any way to merge 4 channels to a RGBA image, with a 4th channel (a separate alpha channel)?
Below is an example of what I've tried
from PIL import Image
# import image A
inputImageA = Image.open(input_imageA_path)
# import image B
inputImageB = Image.open(input_imageB_path)
# split channels
R, G, B, A = inputImageA.split()
alpha_channel = inputImageA.split()[-1]
# merge 4 channels back into a single image
outputImage = Image.merge("RGBA", [R,G,B,alpha_channel])
# save the new image
outputImage.save(ouput_image_path)
In this example the resulting output image only has 3 channels (RGB).
Please see below image for a visual explanation of what I'm trying to do:
Updated Answer
Ok, I think you mean this now:
#!/usr/bin/env python3
from PIL import Image
# Open background image, ensuring RGB
im = Image.open('start.png').convert('RGB')
# Open alpha channel, ensuring single channel
alpha = Image.open('alpha.png').convert('L')
# Add that alpha channel to background image
im.putalpha(alpha)
# Save as TIFF
im.save('result.tif')
Which makes start.png:
plus alpha.png:
into result.tif:
Original Answer
Here's a simple example of creating and saving a 4 channel, RGBA TIFF:
#!/usr/bin/env python3
from PIL import Image, ImageDraw
# Create RGB image full of yellow
w, h = 640, 480
im =Image.new('RGB',(w,h),color=(255,255,0))
# Create alpha channel of white i.e. opaque
alpha =Image.new('L',(w,h),color=255)
# Get drawing context to draw into alpha channel and draw black (i.e. transparent) rectangle
d = ImageDraw.Draw(alpha)
d.rectangle([10,40,200,250],fill=0)
# Add that alpha channel to yellow image
im.putalpha(alpha)
# Save as TIFF
im.save('result.tif')
I figured out a solution to this issue using the OpenCV2 library instead of PIL. See below how I did it:
import cv2
# read original image
original = cv2.imread(original_image_path, cv2.IMREAD_UNCHANGED)
# get dimensions for resizing mask
height, width, channels = original.shape
# read alpha image
alpha = cv2.imread(alpha_path)
# resize alpha image to match original
alpha_resized = cv2.resize(alpha, (height,width))
# split alpha_resized into individual channels
channels = cv2.split(alpha_resized)
# apply to 4th channel of original
original[:,:,3] = channels[0]
# write new image file with alpha channel
cv2.imwrite(output_path,original)

Categories