I have a homework assignment I'm desperate to figure out. We've only spent two lecture days on opencv so I'm going in blind with this.
The assignment is to convert an RGB img to grayscale using the luminance formula 0.02126*R+0.7152*G+0.0722*B
So the type of each pixel should be the same as the original image. We're not allowed to use matplot or PIL which is what I've seen a lot of trying to figure this thing out.
The code I have now outputs just a gray image. So instead of graySCALE, it's only gray. I'm so lost, please help.
import cv2
import numpy as np
def togray():
img = cv2.imread("fruits.jpg")
cv2.imshow('Original',img)
height, width, channels = img.shape
img2 = np.ndarray (shape=(height,width,))
for i in range(height):
for j in range(width):
img2[i,j]=(0*0.2126 + 0.7152*1 + 0.0722*2)
cv2.imshow('Grayscale',img2)
cv2.waitKey(0)
togray()
Try doing img2 = 0.02126*img[:,:,2] + 0.7152*img[:, :,1] + 0.0722*img[:,:,0]
The comment by Julien was wrong for two reasons: (i) The shape of an image is (m, n, 3) in opencv. This explains why that indexing gives you a smaller box. (ii) opencv channels are BGR, not RGB, so you need to swap the 2 and the 0 indices as I did here. (The actual result should not change too much just considering how small the R and B terms contribute).
Related
I have a np.array with grayscale images and I want to apply a colormap, then save the result into a video file.
With this code (or with the commented line) I get a grayscale video anyways. Any idea why I can't have a colormap video?
color_images = np.empty([N, resolution[1], resolution[0], 3])
for i in range(0, N):
cv2.imwrite(gray_images[i])
color_images[i] = cv2.cvtColor(np.float32(gray_images[i]), cv2.COLOR_GRAY2BGR)
#color_images[i] = cv2.merge([gray_images[i], gray_images[i], gray_images[i]])
out = cv2.VideoWriter("video.mp4", cv2.VideoWriter_fourcc(*'mp4v'),
fps, (resolution[0], resolution[1]), 1)
for i in range(0, N):
out.write(np.uint8(color_images[i]))
out.release()
UPDATE: I want to have a colored image so that differences in pixel intensity can be more noticeable. (For instance use the default cmap in plt.imshow ('viridis')).
cvtColor doesn't do that. For any grayscale pixel, it gives you the RGB/BGR pixel that looks gray with the same intensity.
If you want colormaps, you need applyColorMap.
import numpy as np
import cv2 as cv
gray_image = ... # get it from somewhere
colormapped_image = cv.applyColorMap(gray_image, cv.COLORMAP_JET)
learn more here
I have a set of very low-resolution pictures (in .png but I can easily convert them to something else). They all only have black or white pixels, like QR codes.
What I want is to be able to read them as binary matrix (a 1 for a black pixel and a zero for a white one).
I don't need anything more fancy than that, what should I use?
Hi you can use PIL to read the image, and then numpy to convert it to a matrix
from PIL import Image
import numpy as np
im = Image.read("imageName.ext")
im_mat = np.asarray(im)
Alternatively you can do all in one step with opencv
import cv2
img = cv2.imread("imageName.ext")
in both cases you will have a matrix with size WxHxC with H the height in pixels, W the widht and c the number of channels (3 or 4 depending if there's an alpha for transparency).
If your image is black and white and you only want a matrix with size WxH take one channel with
img = img_mat[:,:,0] #8-bit matrix
and last you can binarize that givving an umbral or just by comparing
bin = img> 128
or
bin = img == 255
I corrected this last line I had a typo in it
here I have a small project on which I block for weeks
I Have a display is 3840x2400 monochrome pixels. Nevertheless, it is driven like 1280(RGB)x2400, whereas each RGB subpixel maps to one monochrome pixel.
Therefore, in order to display real 3840x2400 one has to map 3 consecutive pixels of the monochrome image to one pseudo-RGB pixel. This yields a 1280x2400 wide image, where each RGB subpixel corresponds to one real monochrome pixel.
I try to do this in python3.9 with numpy and PIL
The code below:
from PIL import Image
import numpy as np
def TransTo1224(SourcePngFileName, DestPngFileName):
#trans png file from 3840x2400 to 1280X2400(RGB)
print('~~~~~~~')
print(SourcePngFileName)
imgSrc = Image.open(SourcePngFileName)
dataSrc = np.array(imgSrc)
dataDest = dataSrc.reshape(2400,1280,3)
imgDest = Image.fromarray(dataDest, 'RGB')
imgDest.save(DestPngFileName)
TransTo1224("./source/test1.png","./output/test1.png")
I have a error:
dataDest = dataSrc.reshape(2400,1280,3)
ValueError: cannot reshape array of size 27648000 into shape (2400,1280,3)
I don't understand my mistake, if someone can help me, thank you in advance.
try this
dataDest = vv.reshape(2400,1280,3,-1)
or
dataDest = vv.reshape(2400,1280,3,3)
using dataDest = dataSrc.reshape(2400,1280,3) it wont work
ok i solved my problem it came indeed from my input image, the code works with some images but not the one i want to remap. besides i didn't understand where this multiple of 3 came from the
3840x2400x3 = 27648000.
Well my problem came from the mode of the image which was in RGB.
it was enough for me to convert this mode in "L", luminance before making my reshape
from PIL import Image
import numpy as np
def TransTo1224(SourcePngFileName, DestPngFileName):
#trans png file from 3840x2400 to 1280X2400(RGB)
print('~~~~~~~')
print(SourcePngFileName)
imgSrc = Image.open(SourcePngFileName)
imgSrc = imgSrc.convert('L') # <-----
dataSrc = np.array(imgSrc)
dataDest = dataSrc.reshape(2400,1280,3)
imgDest = Image.fromarray(dataDest, 'RGB')
imgDest.save(DestPngFileName)
TransTo1224("./source/test1.png","./output/test1.png")
Thank you all for helping me
I want to convert an image of type CV_64FC1 to CV_8UC1 in Python using OpenCV.
In C++, using convertTo function, we can easily convert image type using following code snippet:
image.convertTo(image, CV_8UC1);
I have searched on Internet but unable to find any solution without errors. Any function in Python OpenCV to convert this?
You can convert it to a Numpy array.
import numpy as np
# Convert source image to unsigned 8 bit integer Numpy array
arr = np.uint8(image)
# Width and height
h, w = arr.shape
It seems OpenCV Python APIs accept Numpy arrays as well. I've not tested it though. Please test it and let me know the result.
For those getting a black screen or lots of noise, you'll want to normalize your image first before converting to 8-bit. This is done with numpy directly as OpenCV uses numpy arrays for its images.
Before normalization, the image's range is from 4267.0 to -4407.0 in my case.
Now to normalize:
# img is a numpy array/cv2 image
img = img - img.min() # Now between 0 and 8674
img = img / img.max() * 255
Now that the image is between 0 and 255, we can convert to a 8-bit integer.
new_img = np.uint8(img)
This can also be done by img.astype(np.uint8).
I faced similar issue and when I trying to convert the image 64F to CV_U8 I would end up with a black screen.
This link will help you understand the datatypes and conversion. Below is the code that worked for me.
from skimage import img_as_ubyte
cv_image = img_as_ubyte(any_skimage_image)
I am trying to access the pixels of a grayscale image. On loading it, I found that the pixel values are transposed as well as the color of the new image 'img.png' is inverted. But ideally, 'img.png' should be same as 'cat.png'. Why are they different?
import numpy as np
from PIL import Image
img=Image.open('cat.png')
pix=img.load()
res_list=[]
img_data= np.zeros((128, 128), dtype=np.uint8)
for i in range(img.size[0]):
for j in range(img.size[1]):
img_data[i,j]=pix[i,j]
img=Image.fromarray(img_data)
img.save('img.png')
Also, when I tried to update img_data as:
img_data[i,j]=255-pix[i,j]
still it wasn't the actual image, but very white image. How can I recover the original image?
The images are:
I agree with gelezko's suggestion to switch indexing order. This will solve the transposition problem.
The color problem appears to occur because the input image isn't actually greyscale. When I tried print img.mode, I got "P" rather than "L". Try explicitly converting to L before doing any work on the pixels.
img=Image.open('cat.png')
img = img.convert("L")
pix=img.load()
Now you should get a properly oriented & colored image:
Right code:
img_data[j,i]=pix[i,j]
Just swap i and j in img_data.