How can I change the background of only white pixels? - python

I have two grayscale images of the same size, one of them is this one:
I'm trying to add a background to this image, which is to just change the white pixels to the respective pixels in the other picture. The best result I've managed to do is just a bitwise and of all the pixels of both pictures but the resultant picture is distorted inside James Bond. I also tried a weighted add between the two pictures but when I increase the weight of the James Bond image, it's white pixels are visible in the resultant image.

To combine with a second image, ensure that both images have the same dimensions (which yours do). They can then be combined
import cv2
img_jb = cv2.imread('james_bond.png')
img_007 = cv2.imread('007_logo.png')
height, width, channels = img_jb.shape
img_007_resized = cv2.resize(img_007, (width, height), interpolation=cv2.INTER_CUBIC)
threshold = img_jb > 240
img_jb[threshold] = img_007_resized[threshold]
cv2.imwrite('james_bond_logo.png', img_jb)
Giving you:
numpy allows you to work on the indexes of an array that match a given criteria. This has the effect of copying pixels from the background image into the foreground image where the foreground image has a value above 240.

Related

Obtain the subtracted area of 2 images via Python OpenCV

I can subtract 2 images by the following codes:
import cv2
original = cv2.imread('image1.png', cv2.IMREAD_UNCHANGED)
tiled = cv2.imread('image2.png', cv2.IMREAD_UNCHANGED)
subtract = cv2.subtract(tiled, original)
cv2.imwrite('subtract.png', subtract)
However, how can I obtain the area (maybe in form of array of pixels, or shapes) that results in black (i.e. after subtraction, the pixel is black color)?
I can only think of looping through each pixel of an image to check whether the pixel value equals to an array of zeros.
Ultimately, I want to change those pixels in black color after subtraction to be transparent.

Change background color for Thresholderd image

I have been trying to write a code to extract cracks from an image using thresholding. However, I wanted to keep the background black. What would be a good solution to keep the outer boundary visible and the background black. Attached below is the original image along with the threshold image and the code used to extract this image.
import cv2
#Read Image
img = cv2.imread('Original.png')
# Convert into gray scale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Image processing ( smoothing )
# Averaging
blur = cv2.blur(gray,(3,3))
ret,th1 = cv2.threshold(blur,145,255,cv2.THRESH_BINARY)
inverted = np.invert(th1)
plt.figure(figsize = (20,20))
plt.subplot(121),plt.imshow(img)
plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(inverted,cmap='gray')
plt.title('Threshold'),plt.xticks([]), plt.yticks([])
Method 1
Assuming the circle in your images stays in one spot throughout your image set you can manually create a black 'mask' image with a white hole in the middle, then overlay it on the final inverted image.
You can easily make the mask image using your favorite image editor's magic wand tool.
I made this1 by also expanding the circle inwards by one pixel to take into account some of the pixels the magic wand tool couldn't catch.
You would then use the mask image like this:
mask = cv2.imread('/path/to/mask.png')
masked = cv2.bitwise_and(inverted, inverted, mask=mask)
Method 2
If the circle does NOT stay is the same spot throughout your entire image set you can try to make the mask from all the fully black pixels in your original image. This assumes that the 'sample' itself (the thing with the cracks) does not contain fully black pixels. Although this will result in the text on the bottom left to be left white.
# make all the non black pixels white
_,mask = cv2.threshold(gray,1,255,cv2.THRESH_BINARY)
1 The original is not the same size as your inverted image and thus the mask I made won't actually fit, you're gonna have to make it yourself.

Replace corresponding white pixels from one image with RGB pixels from another image

I have 2 images - one of the images is binarized i.e. each pixel is either black or white, and the other image is a standard RGB image. Both images are of the same size. For all the white pixels in the first image, I would like to take the corresponding pixels in the RGB image and attach them in place of the white pixels. How can I do this in Python?
Use the binarized image as a binary index for the pixel coordinates:
import numpy as np
my_source_image = np.random.randint(0, 255, (480,640,3), np.uint8) # defined somewhere, assumed to have shape [H,W,3]
my_binarized_image = np.random.randint(0, 2, (480,640), np.uint8) # defined somewhere, assumed to have shape [H,W]
pixel_idx = my_binarized_image.astype(bool)
my_dest_image = np.zeros_like(my_source_image)
my_dest_image[pixel_idx,:] = my_source_image[pixel_idx]
Note that I define the destination image as all-zeroes (if you want a different background color, simply initialize to the color value instead) and then fill in the relevant pixels instead of reusing my_binarized_image as you see to require in your question, because the destination image needs three channels, while the binarized image only has one.
Alternatively, as long as the "background" color is black, you can avoid preallocating a second image and simply zero-out the pixels in the first image instead:
my_dest_image = my_source_image * pixel_idx[...,None]
(The [...,None] adds an extra dimension at the end of pixel_idx to make the pixel-wise multiplication possible)

How to hide overlapping pixels using Pillow?

I have two images of similar dimensions as such:
Since the outer circle should have close to overlapping pixels, I would like to have a resultant image that has the inner circle from image A and the square from image B. I thought inverting image A and then calling PIL.Image.composite(imageA, imageB, mask) would do something but it just gave me a combination of imageA and imageB.
Is there a way to do what I want using Pillow or perhaps using numpy somehow to make white the pixels that are similar between both images?
I think you are looking for an XOR between the two images.
I'll work up to it slowly in case you don't do many logical expression evaluations, so starting with OR, you will get white pixels out as a result where the either image A OR image B has white pixels. Then with an AND, you will get white pixels out where both image A AND image B are white. Finally, with an XOR, you will get white pixels out where either image A or image B but exclusively one or the other but not both have white pixels.
In code, that looks like this:
#!/usr/local/bin/python3
from PIL import Image, ImageChops
# Load up the two images, discarding any alpha channel
im1 = Image.open('im1.png').convert('1')
im2 = Image.open('im2.png').convert('1')
# XOR the images together
result = ImageChops.logical_xor(im1,im2)
result = ImageChops.invert(result)
# Save the result
result.save('result.png')

Edit image pixel by pixel - Python

I have two images, one overlay and one background.
I want to create a new image, by editing overlay image and manipulating it to show only the pixels which have blue colour in the background image.
I dont want to add the background, it is only for selecting the pixels.
Rest part should be transparent.
Any hints or ideas please? PS: I edited result image with paint so its not perfect.
Image 1 is background image.
Image 2 is overlay image.
Image 3 is the check I want to perform. (to find out which pixels have blue in background and making remaining pixels transparent)
Image 4 is the result image after editing.
I renamed your images according to my way of thinking, so I took this as image.png:
and this as mask.png:
Then I did what I think you want as follows. I wrote it quite verbosely so you can see all the steps along the way:
#!/usr/local/bin/python3
from PIL import Image
import numpy as np
# Open input images
image = Image.open("image.png")
mask = Image.open("mask.png")
# Get dimensions
h,w=image.size
# Resize mask to match image, taking care not to introduce new colours (Image.NEAREST)
mask = mask.resize((h,w), Image.NEAREST)
mask.save('mask_resized.png')
# Convert both images to numpy equivalents
npimage = np.array(image)
npmask = np.array(mask)
# Make image transparent where mask is not blue
# Blue pixels in mask seem to show up as RGB(163 204 255)
npimage[:,:,3] = np.where((npmask[:,:,0]<170) & (npmask[:,:,1]<210) & (npmask[:,:,2]>250),255,0).astype(np.uint8)
# Identify grey pixels in image, i.e. R=G=B, and make transparent also
RequalsG=np.where(npimage[:,:,0]==npimage[:,:,1],1,0)
RequalsB=np.where(npimage[:,:,0]==npimage[:,:,2],1,0)
grey=(RequalsG*RequalsB).astype(np.uint8)
npimage[:,:,3] *= 1-grey
# Convert numpy image to PIL image and save
PILrgba=Image.fromarray(npimage)
PILrgba.save("result.png")
And this is the result:
Notes:
a) Your image already has an (unused) alpha channel present.
b) Any lines starting:
npimage[:,:,3] = ...
are just modifying the 4th channel, i.e. the alpha/transparency channel of the image

Categories

Resources