remove foreground from segmented image - python

i have trained a model to provide the segment in image and the output image looks like that
the original image is like that
i have tried opencv to subtract the two images by
image1 = imread("cristiano-ronaldo.jpg")
image2 = imread("cristiano-ronaldo_seg.png")
image3 = cv2.absdiff(image1,image2)
but the output is not what i need , i would like to have cristiano and white background , how i can achieve that

Explanation:
As your files have already the right shape (BGR) and (A) it is very easy to accomplish what you are trying to do, here are the steps.
1) Load original image as BGR (In opencv it's reversed rgb)
2) Load "mask" image as a single Channel A
3) Merge the original images BGR channel and consume your mask image as A Alpha
Code:
import numpy as np
import cv2
# Load an color image in grayscale
img1 = cv2.imread('ronaldo.png',3) #READ BGR
img2 = cv2.imread('ronaldoMask.png',0) #READ AS ALPHA
kernel = np.ones((2,2), np.uint8) #Create Kernel for the depth
img2 = cv2.erode(img2, kernel, iterations=2) #Erode using Kernel
width, height, depth = img1.shape
combinedImage = cv2.merge((img1, img2))
cv2.imwrite('ronaldocombine.png',combinedImage)
Output:

After read the segment image, convert to grayscale, then threshold it to get fg-mask and bg-mask. Then use cv2.bitwise_and to "crop" the fg or bg as you want.
#!/usr/bin/python3
# 2017.11.26 09:56:40 CST
# 2017.11.26 10:11:40 CST
import cv2
import numpy as np
## read
img = cv2.imread("img.jpg")
seg = cv2.imread("seg.png")
## create fg/bg mask
seg_gray = cv2.cvtColor(seg, cv2.COLOR_BGR2GRAY)
_,fg_mask = cv2.threshold(seg_gray, 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)
_,bg_mask = cv2.threshold(seg_gray, 0, 255, cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU)
## convert mask to 3-channels
fg_mask = cv2.cvtColor(fg_mask, cv2.COLOR_GRAY2BGR)
bg_mask = cv2.cvtColor(bg_mask, cv2.COLOR_GRAY2BGR)
## cv2.bitwise_and to extract the region
fg = cv2.bitwise_and(img, fg_mask)
bg = cv2.bitwise_and(img, bg_mask)
## save
cv2.imwrite("fg.png", fg)
cv2.imwrite("bg.png", bg)

Related

How to make cv2 colored image (bgr) to blue range or green range image?

A numpy array (x,y) = unsorted data between(0,10 f.eks.) is coverted to a colored cv2 image bgr and saved.
self.arr = self.arr * 255 #bgr format
cv2.imwrite("img", self.arr)
How to make this cv2 colored image to blue range color (light to dark blue), and how to make it to green range color(light to dark green)?
My thoughts are to go image2np and then do some stuff to the array. Then go back np2image. But I don't know how change values to get expected colours.
I'm not sure if I understand problem but I would convert RGB to grayscale and next create empty RGB (with zeros) and put grayscale as layer B to get "blue range" or as G to get "green range"
import cv2
import numpy as np
img = cv2.imread('test/lenna.png')
cv2.imshow('RGB', img)
h, w = img.shape[:2] # height, width
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow('Gray', gray_img)
blue_img = np.zeros((h,w,3), dtype='uint8')
blue_img[:,:,0] = gray_img # cv2 uses `BGR` instead of `RGB`
cv2.imshow('Blue', blue_img)
green_img = np.zeros((h,w,3), dtype='uint8')
green_img[:,:,1] = gray_img # cv2 uses `BGR` instead of `RGB`
cv2.imshow('Green', green_img)
red_img = np.zeros((h,w,3), dtype='uint8')
red_img[:,:,2] = gray_img # cv2 uses `BGR` instead of `RGB`
cv2.imshow('Red', red_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Image Lenna from Wikipedia.

Having a color, convert entire image to shades of that color

I want to convert the below sample code to a function which will get as input any pixel color, and re-color whole image using shades of the input color, so it will leave the impression of the image with one same color. I don't know how this technique is named, maybe somebody will suggest and will show how this can be done if it is even possible. How to do that in Python ?
import cv2
import numpy as np
src = cv2.imread('image.jpg', cv2.IMREAD_UNCHANGED)
print(src.shape)
# extract blue channel
blue_channel = src[:,:,0]
# create empty image with same shape as that of src image
blue_img = np.zeros(src.shape)
#assign the red channel of src to empty image
blue_img[:,:,0] = blue_channel
Here is another way to colorize the image in Python/OpenCV. Convert to gray, then create a 1D LUT using black, blue (or any other color) and white. Then apply the LUT to the gray image.
Input:
import cv2
import numpy as np
img = cv2.imread("lena.jpg")
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.merge([gray,gray,gray])
# create 1D LUT
# create 1 pixel blue image
black = np.zeros((1, 1, 3), np.uint8)
white = np.full((1, 1, 3), (255,255,255), np.uint8)
blue = np.full((1, 1, 3), (255,0,0), np.uint8)
# append the 3 images
lut = np.concatenate((black, blue, white), axis=0)
# resize lut to 256 values
lut = cv2.resize(lut, (1,256), interpolation=cv2.INTER_CUBIC)
# apply lut to gray
result = cv2.LUT(gray, lut)
# save result
cv2.imwrite('lena_blue2.jpg', result)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Here is one way to colorize the image in Python OpenCV. Convert to gray, then multiply by a blue (or any other color) image.
Input:
import cv2
import numpy as np
img = cv2.imread("lena.jpg")
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
gray = gray.astype(np.float32)
# create blue image
blue = np.full_like(img, (255,0,0), np.float32) / 255
# multiply gray by blue image
result = cv2.multiply(gray, blue)
result = result.astype(np.uint8)
# save result
cv2.imwrite('lena_blue1.jpg', result)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

How to do Histogram Equalization on specific area

I have a image and I want to do HE or CLAHE on specific area of the image.
I already have a mask for the image.
Is there any possible way to do so?
Here is the code to achieve that :
import cv2 as cv
import numpy as np
# Load your color image
#src = cv.imread("___YourImagePath__.jpg",
#cv.IMREAD_COLOR)
#Create random color image
src = np.random.randint(255, size=(800,800,3),dtype=np.uint8)
cv.imshow('Random Color Image',src)
cv.waitKey(0)
# conver to gray
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
# process gray image
equalized = cv.equalizeHist(gray)
# create a mask (binary image with same size as source image )
height,width,depth = src.shape
mask = np.zeros((height,width))
cv.circle(mask,( int(width/2),int(height/2)),int(width/3),1,thickness=-1)
# display mask
cv.imshow('Mask',mask)
cv.waitKey(0)
# Copy processed region using the mask
ProcessedRegion = np.where(mask!=0,equalized,gray)
#display result
cv.imshow('Processed region result', ProcessedRegion)
cv.waitKey(0)
Output :
To do so you need to perform the operation on the pixel intensities of the image which fall within the mask. For that these intensities must be stored separately.
Procedure:
Get the pixel locations of those in white (255), within the mask.
Pick intensity values (0 - 255) from the gray image present in these locations.
Perform your operation (CLAHE or HE) on these intensities. The result is a different collection of intensities.
Place these new intensity values in the collected locations.
Sample:
Input image:
Mask image:
Code:
import cv2
import numpy as np
# read sample image, convert to grayscale
img = cv2.imread('flower.jpg')
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# read mask image as binary image
mask = cv2.imread('flower_mask.jpg', 0)
# Step 1: store locations with value 255 (white)
loc = np.where(mask == 255)
# Step 2: Pick intensity values in these locations from the grayscale image:
values = gray[loc]
# Step 3: Histogram equalization on these values:
enhanced_values = cv2.equalizeHist(values)
# Step 4: Store these enhanced values in those locations:
gray2 = gray_img.copy()
for i, coord in enumerate(zip(loc[0], loc[1])):
gray2[coord[0], coord[1]] = enhanced_values[i][0]
cv2.imshow('Enhanced image', gray2)
Enhance image:
Grayscale image:

How to uniform the color and texture of a face

I'm trying to cartoonify a face using opencv.Here's the original image
Currently I'm doing
Downscaling the image, applying bifilter and upscaling back to original
Then converting RGB of original image to grayscale and followed
medianblur to reduce nice
Apply Adaptive Threshold to create edgemask
Combining the image obtained from step1 with the edge mask with
bitmap
Here's the output
Then applied non-photorealistic rendering using OpenCV. Here's the final output
I want to generate face with uniform color(remove light reflection as well)without affecting the eyes, mouth. How can I achieve that either by tweaking my current code or another possible approach in opencv(python)
Based on: https://www.pyimagesearch.com/2014/07/07/color-quantization-opencv-using-k-means-clustering/
Here is a code that does what you are looking for:
import cv2
import numpy as np
from sklearn.cluster import MiniBatchKMeans
n = 32
# read image and convert to gray
img = cv2.imread('./obama.jpg',cv2.IMREAD_COLOR)
img = cv2.resize(img, (0,0), fx=.2, fy=.2)
img = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
(h, w) = img.shape[:2]
img =np.reshape(img, (img.shape[0]* img.shape[1], 3))
clt = MiniBatchKMeans(n_clusters=n)
labels = clt.fit_predict(img)
quant = clt.cluster_centers_.astype("uint8")[labels]
quant = np.reshape(quant, (h,w,3))
img = np.reshape(img, (h,w,3))
quant = cv2.cvtColor(quant, cv2.COLOR_LAB2BGR)
img = cv2.cvtColor(img, cv2.COLOR_LAB2BGR)
double = np.hstack([img, quant])
while True:
cv2.imshow('img', double)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
You can use this tutorial to apply the color quantization only to boxes containing faces.
https://realpython.com/face-recognition-with-python/

NumPy/OpenCV 2: how do I crop non-rectangular region?

I have a set of points that make a shape (closed polyline). Now I want to copy/crop all pixels from some image inside this shape, leaving the rest black/transparent. How do I do this?
For example, I have this:
and I want to get this:
*edit - updated to work with images that have an alpha channel.
This worked for me:
Make a mask with all black (all masked)
Fill a polygon with white in the shape of your ROI
combine the mask and your image to get the ROI with black everywhere else
You probably just want to keep the image and mask separate for functions that accept masks. However, I believe this does what you specifically asked for:
import cv2
import numpy as np
# original image
# -1 loads as-is so if it will be 3 or 4 channel as the original
image = cv2.imread('image.png', -1)
# mask defaulting to black for 3-channel and transparent for 4-channel
# (of course replace corners with yours)
mask = np.zeros(image.shape, dtype=np.uint8)
roi_corners = np.array([[(10,10), (300,300), (10,300)]], dtype=np.int32)
# fill the ROI so it doesn't get wiped out when the mask is applied
channel_count = image.shape[2] # i.e. 3 or 4 depending on your image
ignore_mask_color = (255,)*channel_count
cv2.fillPoly(mask, roi_corners, ignore_mask_color)
# from Masterfool: use cv2.fillConvexPoly if you know it's convex
# apply the mask
masked_image = cv2.bitwise_and(image, mask)
# save the result
cv2.imwrite('image_masked.png', masked_image)
The following code would be helpful for cropping the images and get them in a white background.
import cv2
import numpy as np
# load the image
image_path = 'input image path'
image = cv2.imread(image_path)
# create a mask with white pixels
mask = np.ones(image.shape, dtype=np.uint8)
mask.fill(255)
# points to be cropped
roi_corners = np.array([[(0, 300), (1880, 300), (1880, 400), (0, 400)]], dtype=np.int32)
# fill the ROI into the mask
cv2.fillPoly(mask, roi_corners, 0)
# The mask image
cv2.imwrite('image_masked.png', mask)
# applying th mask to original image
masked_image = cv2.bitwise_or(image, mask)
# The resultant image
cv2.imwrite('new_masked_image.png', masked_image)
Input Image:
Mask Image:
Resultant output image:

Categories

Resources