How to convert a Binary Image to Grayscale and RGB using python? - python

I am working on hair removal from skin lesion images. Is there any way to convert binary back to rgb?
Original Image:
Mask Image:
I just want to restore the black area with the original image.

As I know binary images are stored in grayscale in opencv values 1-->255.
To create „dummy“ RGB images you can do:
rgb_img = cv2.cvtColor(binary_img, cv.CV_GRAY2RGB)
I call them „dummy“ since in these images the red, green and blue values are just the same.

Something like this, but your mask is the wrong size (200x200 px) so it doesn't match your image (600x450 px):
#!/usr/local/bin/python3
from PIL import Image
import numpy as np
# Open the input image as numpy array
npImage=np.array(Image.open("image.jpg"))
# Open the mask image as numpy array
npMask=np.array(Image.open("mask2.jpg").convert("RGB"))
# Make a binary array identifying where the mask is black
cond = npMask<128
# Select image or mask according to condition array
pixels=np.where(cond, npImage, npMask)
# Save resulting image
result=Image.fromarray(pixels)
result.save('result.png')

I updated the Daniel Tremer's answer:
import cv2
opencv_rgb_img = cv2.cvtColor(opencv_image, cv2.COLOR_GRAY2RGB)
opencv_image would be two dimension matrix like [width, height] because of binary.
opencv_rgb_img would be three dimension matrix like [width, height, color channel] because of RGB.

Related

How to change specific pixel value in grayscale image?

I want to change the pixel value of a grayscale image using OpenCV.
Assume that I have a grayscale image and I want to convert all its pixel to 0 value one at a time. So that the resultant image is completely black. I tried this but there is no change in the image:
image = cv2.imread('test_image.png',0)
for i in range(image.shape[0]):
for j in range(image.shape[1]):
image[i, j] = 0
Result:
display the updated image
In most cases, you want to avoid using double for loops to modify pixel values since it is very slow. A better approach is to use Numpy for pixel modification since OpenCV uses Numpy arrays to display images. To achieve your desired result, you can use np.zeros to create a completely black image with the same shape as the original image.
import cv2
import numpy as np
image = cv2.imread("test_image.png", 0)
black = np.zeros(image.shape, np.uint8)
cv2.imshow('image', image)
cv2.imshow('black', black)
cv2.waitKey(0)
For example with a test image. Original (left), result (right)
I would suggest you to always try manipulating the copy of an image so that the image doesn't get affected in the wrong way. Coming to your question, you can do the following:
import cv2
image = cv2.imread('test_image.png',0)
#Creating a copy of the image to confirm right operation is performed on the image.
image_copy = image.copy()
image_copy[:,:] = [0] #Setting all values to 0.

meaning of draw line's argument in OpenCv

I have some question about why img initialize like following code in document
import numpy as np
import cv2
# Create a black image
img = np.zeros((512,512,3), np.uint8)
# Draw a diagonal blue line with thickness of 5 px
cv2.line(img,(0,0),(511,511),(255,0,0),5)
it create a 3d array for img, I know 512,512 means image size, but why do we need "3" in third dimension?
The third component is used for the color channels.
In OpenCV it is default a BRG Color model.
In your example you created an Image 512x512 Pixel with 24bit color depth.
So if you just want a Gray scale image you can replace the 3 by a 1.

opencv python copy mask region (black or white pixels) onto a BGR image region

In OpenCV python, say we read an image with cv2.imread and get a BGR numpy array. We next generate a mask with the cv2.inRange command. The mask has the same width/height and each mask pixel is either black or white.
I want to copy a region from the mask (taken as an image of black and white pixels) onto a region of the color image.
How do I do that? This does not work
img[10:20,10:20] = mask[10:20,10:20]
Must I convert the mask to BGR image first? If so how?
Edit: I do not want to apply the whole mask to the image as in apply mask to color image. Another way to say what I want: see the mask as a black and white image. I want to copy a region of that image (as a set of black or white pixels) onto another image. The resulting image will be a color image except for one smaller rectangular region that contains only black or white pixels. The result will be similar to if I in photoshop copy a rectangular area of a black/white image and past that rectangle onto an area of a color image.
(I'm new to OpenCV)
If you try to do it with a single channel (grayscale) mask directly, the shapes of the array slices will not be the same, and the operation will fail.
>>> img[10:20,10:20] = mask[10:20,10:20]
ValueError: could not broadcast input array from shape (10,10) into shape (10,10,3)
You have to convert the mask to BGR, which will make it 3 channels, like the original image.
>>> bgr_mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
>>> img[10:20,10:20] = bgr_mask[10:20,10:20]

Stitching images together Opencv -Python

My program takes in an image and crops the image into seperate images according to the scale parameter, e.g. scale = 3 produces 9 images of equal size. I then work out mean rgb of each cropped image and set all pixel values in the image equal to the mean rgb value.
I am wondering how I can stich the cropped images back together to output one image? Which in this case would be a grid of nine different colours.
Here is my code:
# import packages
import numpy as np
import cv2
import dateutil
import llist
from matplotlib import pyplot as plt
import argparse
#Read in image
img = cv2.imread('images/0021.jpg')
scale = 3
#Get x and y components of image
y_len,x_len,_ = img.shape
mean_values = []
for y in range(scale):
for x in range(scale):
#Crop image 3*3 windows
cropped_img=img[(y*y_len)/scale:((y+1)*y_len)/scale,
(x*x_len)/scale:((x+1)*x_len)/scale]
mean_val=cv2.mean(cropped_img)
mean_val=mean_val[:3]
#Set cropped img pixels equal to mean RGB
cropped_img[:,:,:] = mean_val
cv2.imshow('cropped',cropped_img)
cv2.waitKey(0)
#Print mean_values array
#mean_values.append([mean_val])
#mean_values=np.asarray(mean_values)
#print mean_values.reshape(3,3,3)
As it stands the nested for loop iterates over the image and outputs the images (which are just blocks of one colour) in the order that I want to stitch them together, but im not sure how to achieve this.
I don't know if such things exist in OpenCV, but in ImageMagick you can simply resize the image down to the tile-size (which will implicitly average the pixels) and the re-scale the image back up to the original size without interpolation - also called Nearest Neighbour Resampling. Like this:
# Get original width and height
identify -format "%wx%h" face1.jpg
500x529
# Resize down to, say 10x10 and then back up to the original size
convert face1.jpg -resize 10x10! -scale "${geom}"! out.jpg
Per your original, 3x3 becomes:
convert face1.jpg -resize 3x3! -scale "${geom}"! out.jpg
and 3x5 becomes:
convert face1.jpg -resize 3x5! -scale "${geom}"! out.jpg

Convert a 2D numpy array into a 3d numpy array representing a grayscaled image

I am using OpenCV with numpy and Python. I have a 2D uint8 numpy array. The values represent the local densities of over-threshold pixels from a thresholded image. I would like to convert this into a 3-dimensional RGB image with all RGB values set the same, so basically a grayscale image where the maximum value gets (255,255,255) and everything else is scaled accordingly. (I need RGB because this seems to be the only kind of image I can write to video with OpenCV). What is the most efficient way to do this?
I assume that you have a 2D grayscale image, something like:
>>> import cv2
>>> img_gray = cv2.imread('./440px-Lenna.png', cv2.CV_LOAD_IMAGE_GRAYSCALE) # image take from http://en.wikipedia.org/wiki/Lenna
Now img_gray contains a gray scale image:
>>> print(img_gray.shape)
(440, 440)
You can convert the image to BGR in an efficient way using cv2.cvtColor:
>>> img_bgr = cv2.cvtColor(img_gray, cv2.COLOR_GRAY2BGR)
>>> print(img_bgr.shape)
(440, 440, 3)

Categories