How to render grayscale numpy array as PyQt6 QImage? - python

Given a variable blurmap that is a grayscale 1440x1080 numpy array that when saved with imageio results in this image:
https://i.stack.imgur.com/AxKha.jpg
What is causing PyQt to render it like this?
https://i.stack.imgur.com/8pnlP.png
The relevant code to load the data as a QImage/QPixmap is as follows:
h, w = blurmap.shape
self.blurmap = QtGui.QImage(blurmap, w, h, QtGui.QImage.Format.Format_Grayscale8)
self.image_3.setPixmap(QtGui.QPixmap(self.blurmap))
I've tried various formats and even the above code is already from other questions that have asked similar problems, but I can't seem to get it to render correctly no matter what I do. I am able to load RGB888 files in the same project with slight variation to the code but this greyscale image is not working at all. For example here is the relevant code for loading the RGB888 images which I have also tried to adapt for the grayscale image to no avail:
h, w, c = self.rawInput.shape
bytesPerLine = 3 * w
self.baseImg = QtGui.QImage(self.rawInput.data, w, h, bytesPerLine, QtGui.QImage.Format.Format_RGB888)
self.image_1.setPixmap(QtGui.QPixmap(self.baseImg))
As far as I'm aware the only difference is with the bytesPerLine variable added which I'm to believe is simply taking into account the 3 channels of the RGB image, which this grayscale should not require

Related

Python PIL read/open TIFF is black only

I try to read a TIFF file with pillow/PIL (7.2.0) in Python (3.8.3), e.g. this image.
The resulting file seems to be corrupted:
from PIL import Image
import numpy as np
myimage = Image.open('moon.tif')
myimage.mode
# 'L'
myimage.format
# 'TIFF'
myimage.size
# (358, 537)
# so far all good, but:
np.array(myimage)
# shows only zeros in the array, likewise
np.array(myimage).sum()
# 0
It doesn't seem to be a problem of the conversion to numpy array only, since if I save it to a jpg (myimage.save('moon.jpg')) the resulting jpg image has the appropriate dimensions but is all black, too.
Where did I do wrong or is it a bug?
I am not an expert in coding but i had same problem and found the TIFF file has 4 layers. R, G ,B and Alpha. When you convert it using PIL it is black.
try to view the image as plt.imshow(myimage[:, :, 0])
you could also remove the Alpha layer by saving the read image ( i used plt.imread('image')) and then saving it as image=image[:,:,3]. Now its a RGB image.
I don't know if i answered your question, but i felt this info might be of help.

Python - Find out aspect ratio of image

I'm writing a script that automatically lets me download images from a website and set them as my background. But I only want landscape/horizontal pictures, is there a way for python to see the aspect ratio of an image and then discard them based on whether it's horizontal or vertical? And would this be easier to do after downloading the pictures, or before using Selenium?
You can achieve this with the Python OpenCV Library, available here.
With openCV you can read the width and height of your choice image. Just like this:
import cv2
im = cv2.imread('www.your_image_url.com')
h, w, c = im.shape
# h is the image height, and w is the width. Note that for portrait images w is always less that h
# then pass your download condition
if w < h:
# do not download image code
else:
# download image code

Selecting the Data Matrix from a Image and Decoding it

I have the image as attached. I tried using the below code and it outputs the correct values for most of the images. But however it takes a long time to decode.
import cv2
from pylibdmtx.pylibdmtx import decode
import ctypes
from PIL import Image
decode(Image.open("1591106831_festo.jpg"))
I believe if I can select only the particular section of the image that contains the data matrix and input it to the pylibdmtx library it might be more accurate and faster.
But currently i'm unable to figure out how to select the section of image with data matrix. Could you please help me out. Thanks.
Expected output for the attached DataMatrix is (91)4608
What about simply using cv2 and pylibdmtx as follows
import cv2
from pylibdmtx.pylibdmtx import decode
image = cv2.imread("1591106831_festo.jpg")
h, w = image.shape[:2]
decdd = decode((image[:, :, :1].tobytes(), w, h))
print(decdd)
# [Decoded(data=b'(91)4608', rect=Rect(left=650, top=522, width=-82, height=86))]
Which is probably faster that what you currently have in hand since we 1) provide decode with not-to-be-guessed parameters and 2) do image[:, :, :1], which means that one only deals with the first BGR layer, the blue one, clearly sufficient for barcodes.
For the sake of comparison, decode(Image.open("1591106831_festo.jpg")) returns
[Decoded(data=b'(91)4608', rect=Rect(left=650, top=522, width=-82, height=86))]
i.e. the exact same inference.
Something you can do is limit the number of barcodes you want to get, using the max_count argument,
>>> decode(Image.open("1591106831_festo.jpg"), max_count=1)
[Decoded(data=b'(91)4608', rect=Rect(left=522, top=629, width=86, height=82))]

Error when overlaying two images in OpenCV and or PIL

I've tried overlaying two images in openCV both in openCV and in PIL, but to no avail. I'm using a 1000x1000x3 array of np.zeros for the background (aka, a black background) and this random image of my monitor, but I really can't get it to work for some reason unbeknownst to me.
Trying with OpenCV only: (result(if you pay attention, you can see a couple of weird lines and dots in the middle))
base_temp = np.zeros((1000,1000,3))
foreground_temp = cv2.imread('exampleImageThatILinkedAbove.png')
base_temp[offset_y:offset_y+foreground_temp.shape[0], offset_x:offset_x+foreground_temp.shape[1]] = foreground_temp
Trying with PIL: (The result is literally the same as the OpenCV version)
base_temp = cv2.convertScaleAbs(self.base) #Convert to uint8 for cvtColor
base_temp = cv2.cvtColor(base_temp, cv2.COLOR_BGR2RGB) #PIL uses RGB and OpenCV uses BGR
base_temp = Image.fromarray(base_temp) #Convert to PIL Image
foreground_temp = cv2.cvtColor(cv2.convertScaleAbs(self.last_img), cv2.COLOR_BGR2RGB)
foreground_temp = Image.fromarray(foreground_temp)
base_temp.paste(foreground_temp, offset)
I'm using python3.5 and and OpenCV3.4 on Windows 10, if that's any help.
I'd like to avoid any solutions that require saving the cv2 images and then reloading them in another module to convert them but if it's unavoidable that's okay too. Any help would be appreciated!
If you check the type of base_temp, you will see it is float64 and that is going to cause you problems when you try to save it as a JPEG which expects unsigned 8-bit values.
So the solution is to create your base_temp image with the correct type:
base_temp = np.zeros((1000,1000,3), dtype=np.uint8)
The complete code and result look like this:
import cv2
import numpy as np
from PIL import Image
# Make black background - not square, so it shows up problems with swapped dimensions
base_temp=np.zeros((768,1024,3),dtype=np.uint8)
foreground_temp=cv2.imread('monitor.png')
# Paste with different x and y offsets so it is clear when indices are swapped
offset_y=80
offset_x=40
base_temp[offset_y:offset_y+foreground_temp.shape[0], offset_x:offset_x+foreground_temp.shape[1]] = foreground_temp
Image.fromarray(base_temp).save('result.png')

Can someone explain me different type of modes of image?

enter image description here
I am new to the this image processing stuff. Why I am asking this question is because I have a code which works for RGB mode but doesnt for P mode ?
So I came to conclusion that it is something related to modes. I did some basic research on modes.but did not find any simple explanation. Will be helpful if someone can help me understand this.
CODE:
image=Image.open('image.png')
image.load()
image_data = np.asarray(image)
image_data_bw = image_data.max(axis=2)
non_empty_columns = np.where(image_data_bw.max(axis=0)>0)[0]
non_empty_rows = np.where(image_data_bw.max(axis=1)>0)[0]
cropBox = (min(non_empty_rows), max(non_empty_rows), min(non_empty_columns), max(non_empty_columns))
image_data_new = image_data[cropBox[0]:cropBox[1]+1, cropBox[2]:cropBox[3]+1 , :]
new_image = Image.fromarray(image_data_new)
new_image.save('cropped_image.png')
Codesource
Input to the code following Image:
Output should be like the following image(It is cropped to the edges of the picture. Please click on the image for understanding):
This Image is in RGBA mode.so the code is working fine for such images. But not with the image in P mode.
ERROR:
Error I get with P mode:
axis 2 is out of bounds for array of dimension 2
The answer you found greatly overcomplicates the process, by using numpy. The PIL library supports this usecase natively, with the image.getbbox() and image.crop() methods:
cropbox = image.getbbox()
new_image = image.crop(cropbox)
This works for all the different modes, regardless. The cropbox produced by image.getbbox() is exactly the same size as the one produced by the numpy route.
from PIL import Image
img = Image.open('Image.png')
print(x,y)
img.show()
cropbox_1 = img.getbbox()
new_image_1 = img.crop(cropbox_1)
new_image_1.save('Cropped_image,png')
new_image_1.show()
This code completely crops the image to the edges. Only if the images are having alpha channel, you might have to remove that channel by converting it.
ex. If it is a RGBA mode make it RGB and then use getbbox().
img = image.convert('RGB')
cropbox = img.getbbox()
image_1 = img.crop(cropbox)
addition of this should do the task.

Categories