Create & Save 16 bits RGB image with OpenCV [duplicate] - python

This question already has answers here:
OpenCV - Reading a 16 bit grayscale image
(4 answers)
Closed 3 years ago.
I'm generating an image that contains all the possible color values of certain bit depth on RGB (same value on 3 channels, so it looks grayscale), creating an easy to read pattern, this code might be usefull (It generates a uint16 NumPy array):
import cv2
import numpy as np
w = 1824
h= 948
bits = 16
max_color = pow(2,bits)
hbar_size = round((w*h)/(max_color))
num_bars = round(h/hbar_size)
color = 0
image_data = np.zeros((h, w, 3)).astype(np.uint16)
for x in range(0,num_bars+1):
if((x+1)*hbar_size < h):
for j in range(0,w):
color += 1
for i in range(x*hbar_size , (x+1)*hbar_size):
#print(i)
image_data[i, j] = color
else:
for j in range(0,w):
color += 1
for i in range(x*hbar_size , h):
#print(i)
image_data[i, j] = min(color , max_color)
The problem is:
When I save it using cv2.imwrite('allValues.png',image_data) I can see the image, which seems to be right BUT it is actually saved on 8 bits depth (when i read it with img = cv2.imread('allValues.png') I get a uint8 NumPy array).
The Question is:
Is there an apropiate way of write/read 16 bits RGB images on OpenCV for python?
Is the png format the problem?

It is saving in 16bit, but it converts to 8bit automatically when loaded so that you can view it on your screen. You can bypass that functionality by using
im = cv2.imread('allValues.png',-1)

Related

OpenCV RGB to CMYK conversion not producing expected results

I am trying to separate the CMYK channels from an RGB image to be used later.
The question np.dstack() does not recreate original image in OpenCV is my earlier question using a test image. I decided to run it again with a different image and it returned some results and I don't know what's happening.
The issue with this is the results do not match the original image as they are supposed to.
Left: Original Image
Top Right: Result as .jpg
Bottom Right: Result as .tif
Code:
import cv2
import numpy as np
# Load image
bgr = cv2.imread('xpwallpaper.jpg')
# Make float and divide by 255 to give BGRdash
bgrdash = bgr.astype(np.float)/255.
# Calculate K as (1 - whatever is biggest out of Rdash, Gdash, Bdash)
K = 1 - np.max(bgrdash, axis=2)
# Calculate C
C = (1-bgrdash[...,2] - K)/(1-K)
# Calculate M
M = (1-bgrdash[...,1] - K)/(1-K)
# Calculate Y
Y = (1-bgrdash[...,0] - K)/(1-K)
# Combine 4 channels into single image and re-scale back up to uint8
CMYK = (np.dstack((C,M,Y,K))*255).astype(np.uint8)
cv2.imwrite("CMYK.jpg", CMYK)

Manipulate images with Python for image quiz (big pixels areas) [duplicate]

This question already has answers here:
How to pixelate a square image to 256 big pixels with python?
(4 answers)
Closed 2 years ago.
I want to manipulate some images with Python for a little quiz game. The quiz player should guess the image.
I think an image with only big pixel areas would be fine. I want a similar result like this: https://www.ixxiyourworld.com/media/2387631/ixsp110-van-gogh-petrol-pixel-03.jpg
Lets try PIL to first downscale the image massively to a given kernel size, then upscale with NEAREST back to the same size -
from PIL import Image
from numpy import asarray
img = Image.open("van_gogh.jpg", mode='r')
factor = 100
kernel = (img.height//factor, img.width//factor)
pixelated = img.resize(kernel,resample=Image.BICUBIC) #downsample
pixelated = pixelated.resize(img.size,Image.NEAREST) #upsample
#Grids
grid_color = [255,255,255]
dx, dy = factor, factor
g = np.asarray(pixelated).copy()
g[:,::dy,:] = grid_color
g[::dx,:,:] = grid_color
pixelated2 = Image.fromarray(g)
pixelated2
Increasing the factor here, will pixelate the image further.
factor = 100

Array to Image conversion

I've been struggling for hours now with this tiny problem.
I've been trying to do some image modification. Here is the code snipet :
import numpy as np
from PIL import Image
#Conversion image array
img = Image.open('lena.jpg')
array = np.array(img)
def niv_de_gris(img):
height = len(img)
width = len(img[0])
#Creation tableau vide
new_img = ([[[0 for i in range(3)] for j in range(width)] for k in range(height)])
for i in range(height):
for j in range(width):
m = np.mean(img[i][j])
for k in range(3):
new_img[i][j][k] = int(m)
return np.array(new_img)
array_gris = niv_de_gris(array)
img_gris = Image.fromarray(array_gris) #problem is here !!
the first conversion works perfectly fine : it takes an image an converts it into an array. The program runs flowlessly, the image modification works, it sends me back an array of the image converted in gray levels.
Yet when I want to convert this array into an image to .show() it, i get this error :
Error screenshot
Can anybody help me figure this out pls?
Have a nice day!
Array to PIL may need to ensure pixel values are not 0-1 but 0-255, type is unit8 and then define the mode as 'RGB'.
Try using -
array_gris = niv_de_gris(array) * 255 #Skip this step if pixels are 0-255 already
array_gris = array_gris.astype(np.uint8)
img_gris = Image.fromarray(array_gris, mode='RGB')
That worked for me on a random image that I choose. Depending on the function and the image, I believe the only real important step is to ensure they are legit pixel values and that type is uint8.

Setting pixels values in OpenCV Python

How fast change pixels values? In C# what i need to do is only use GetPixel() to get pixel value and SetPixel() to change it (its pretty easy to use but slow, MarshallCopy and Lock/UnlockBits is much faster).
In this code, i marking black pixels as 1 and white pixels as 0
import tkFileDialog
import cv2
import numpy as np
from matplotlib import pyplot as plt
path = tkFileDialog.askopenfilename()
bmp = cv2.imread(path) #reading image
height, width, channels = bmp.shape
if channels == 3:
bmp = cv2.cvtColor(bmp, cv2.COLOR_BGR2GRAY) #if image have 3 channels, convert to BW
bmp = bmp.astype('uint8')
bmp = cv2.adaptiveThreshold(bmp,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
cv2.THRESH_BINARY,11,2) #Otsu thresholding
imageData = np.asarray(bmp) #get pixels values
pixelArray = [[0 for y in range(height)] for x in range(width)] #set size of array for pixels
for y in range(len(imageData)):
for x in range(len(imageData[0])):
if imageData[y][x] == 0:
pixelArray[y][x] = 1 #if black pixels = 1
else:
pixelArray[y][x] = 0 #if white pixels = 0
In c#, it can looks like this:
for (y = 0; y < bmp.Height-1; y++)
{
for (x = 0; x < bmp.Width-1; x++)
{
if (pixelArray[y, x] == 1)
newImage.SetPixel(x, y, Color.Black); //printing new bitmap
else
newImage.SetPixel(x, y, Color.White);
}
}
image2.Source = Bitmap2BitmapImage(newImage);
In the next step i will marking countour pixels as "2", but now i want to ask you, how to set new image in python from my specific value and then, display it? For experimental purpose, i want to invert image (from B&W to W&B) only by byte valuse. Can you help me how to do it?
EDIT1
I think i found a solution, but i have GREYSCALE image with one channel (i think thats how it works when i using cv2.cvtColor to convert 3 channels image to greyscale image). The function like this:
im[np.where((im == [0,0,0]).all(axis = 2))] = [0,33,166]
Could work pretty well, but how to make that function work with greyscale image? I want to set some black pixels (0) into White (255)
For a single channel image (gray scale image) use the following:
First create a copy of the gray image:
gray_2 = gray.copy()
Now assign black pixels to be white:
gray_2[np.where(gray == 0)] = 255

Display interleaved image in python [duplicate]

So I have a set of data which I am able to convert to form separate numpy arrays of R, G, B bands. Now I need to combine them to form an RGB image.
I tried 'Image' to do the job but it requires 'mode' to be attributed.
I tried to do a trick. I would use Image.fromarray() to take the array to image but it attains 'F' mode by default when Image.merge requires 'L' mode images to merge. If I would declare the attribute of array in fromarray() to 'L' at first place, all the R G B images become distorted.
But, if I save the images and then open them and then merge, it works fine. Image reads the image with 'L' mode.
Now I have two issues.
First, I dont think it is an elegant way of doing the work. So if anyone knows the better way of doing it, please tell
Secondly, Image.SAVE is not working properly. Following are the errors I face:
In [7]: Image.SAVE(imagefile, 'JPEG')
----------------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/media/New Volume/Documents/My own works/ISAC/SAMPLES/<ipython console> in <module>()
TypeError: 'dict' object is not callable
Please suggest solutions.
And please mind that the image is around 4000x4000 size array.
rgb = np.dstack((r,g,b)) # stacks 3 h x w arrays -> h x w x 3
To also convert floats 0 .. 1 to uint8 s,
rgb_uint8 = (np.dstack((r,g,b)) * 255.999) .astype(np.uint8) # right, Janna, not 256
I don't really understand your question but here is an example of something similar I've done recently that seems like it might help:
# r, g, and b are 512x512 float arrays with values >= 0 and < 1.
from PIL import Image
import numpy as np
rgbArray = np.zeros((512,512,3), 'uint8')
rgbArray[..., 0] = r*256
rgbArray[..., 1] = g*256
rgbArray[..., 2] = b*256
img = Image.fromarray(rgbArray)
img.save('myimg.jpeg')
rgb = np.dstack((r,g,b)) # stacks 3 h x w arrays -> h x w x 3
This code doesnt create 3d array if you pass 3 channels. 2 channels remain.
Convert the numpy arrays to uint8 before passing them to Image.fromarray
Eg. if you have floats in the range [0..1]:
r = Image.fromarray(numpy.uint8(r_array*255.999))
Your distortion i believe is caused by the way you are splitting your original image into its individual bands and then resizing it again before putting it into merge;
`
image=Image.open("your image")
print(image.size) #size is inverted i.e columns first rows second eg: 500,250
#convert to array
li_r=list(image.getdata(band=0))
arr_r=np.array(li_r,dtype="uint8")
li_g=list(image.getdata(band=1))
arr_g=np.array(li_g,dtype="uint8")
li_b=list(image.getdata(band=2))
arr_b=np.array(li_b,dtype="uint8")
# reshape
reshaper=arr_r.reshape(250,500) #size flipped so it reshapes correctly
reshapeb=arr_b.reshape(250,500)
reshapeg=arr_g.reshape(250,500)
imr=Image.fromarray(reshaper,mode=None) # mode I
imb=Image.fromarray(reshapeb,mode=None)
img=Image.fromarray(reshapeg,mode=None)
#merge
merged=Image.merge("RGB",(imr,img,imb))
merged.show()
`
this works well !
If using PIL Image convert it to array and then proceed with the below, else using matplotlib or cv2 perform directly.
image = cv2.imread('')[:,:,::-1]
image_2 = image[10:150,10:100]
print(image_2.shape)
img_r = image_2[:,:,0]
img_g = image_2[:,:,1]
img_b = image_2[:,:,2]
image_2 = img_r*0.2989 + 0.587*img_g + 0.114*img_b
image[10:150,10:100,0] = image_2
image[10:150,10:100,1] = image_2
image[10:150,10:100,2] = image_2
plt.imshow(image,cmap='gray')

Categories

Resources