How to convert a pygame Surface to a PIL Image? - python

I'm using PIL to transform a portion of the screen perspectively.
The original image-data is a pygame Surface which needs to be converted to a PIL Image.
Therefore I found the tostring-function of pygame which exists for that purpose.
However the result looks pretty odd (see attached screenshot). What is going wrong with this code:
rImage = pygame.Surface((1024,768))
#draw something to the Surface
sprite = pygame.sprite.RenderPlain((playboard,))
sprite.draw(rImage)
pil_string_image = pygame.image.tostring(rImage, "RGBA",False)
pil_image = Image.fromstring("RGBA",(660,660),pil_string_image)
What am I doing wrong?

As I noted in a comment, pygame documentation
for pygame.image.fromstring(string, size, format, flipped=False) says “The size and format image must compute the exact same size as the passed string buffer. Otherwise an exception will be raised”. Thus, using (1024,768) in place of (660,660), or vice versa – in general, the same dimensions for the two calls – is more likely to work. (I say “more likely to work” instead of “will work” because of I didn't test any cases.)
The reason for suspecting a problem like this: The strange look of part of the image resembles a display screen which is set to a raster rate it can't synchronize; ie, lines of the image start displaying at points other than at the left margin; in this case because of image line lengths being longer than display line lengths. I'm assuming the snowflakes are sprites, generated separately from the distorted image.

Related

Image to Text - Pytesseract struggles with digits on windows

I'm trying to preprocess frames of a game in real-time for a ML project.
I want to extract numbers from the frame, so I chose Pytesseract, since it looked quite good with text.
Though, no matter how clear I make the text, it won't read it correctly.
My code looks like this:
section = process_screen(screen_image)[1]
pixels = rgb_to_bw(section) #Makes the image grayscale
pixels[pixels < 200] = 0 #Makes all non-white pixels black
tess.image_to_string(pixels)
=> 'ye ml)'
At best it outputs "ye ml)" when I don't specify I want digits, and when I do, it outputs nothing at all.
The non-processed game image looks like so:
The "pixels" image looks like so :
Thanks to Alex Alex, I inverted the image, and got this
And got "2710", which is better, but still not perfect.
You must invert the image before recognition.

Python image manipulation using PIL(LSB)

I have recently started studying steganography and I've come across a problem that I just don't seem to understand. Basically, the image is a png which contains a hidden flag in it.
When you extract the bit planes from the image, you can see that there's an image in the blue and green planes that you can see in the red one. To reveal the flag in clear text, you have to remove those images from the red one by XORing the LSB or something. I am not totally sure.
This is what the image in the red plane looks like if you don't remove the others.
My question is how do I go about doing this kind of thing? This is the image in question.
Actually the hidden image is in the lowest 3 bit planes. Doing a full bit decomposition makes that clear.
Start by loading the image to a numpy array, which will have dimensions MxNx3.
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
img = Image.open('stego.png')
data = np.array(img)
All you have to do now is XOR each colour plane with another and then keep the 3 least significant bits (lsb).
extracted = (data[...,0] ^ data[...,1] ^ data[...,2]) & 0x07
plt.imshow(extracted)
plt.show()
In case it wasn't obvious, the & 0x07 part is an AND operation with the binary number 00000111, just written in hexadecimal for conciseness.
If you don't keep all 3 lsb, then you'll either be missing some letters in the solution, or everything will be there but some edges won't be as smooth. The first of these is critically important.

Image processing - filtering background light [Python pref]

I would like to remove the background light gradient from the following image, such that the lightening would become more homogeneous, the interesting objects being the kind of "cones" seen from the top.
Image:
I also have an image "background" without the cones :
I tried the simplest thing , which is to convert these images in grayscale and the substracting it but the result is pretty ... (really) bad, using :
img = np.array(Image.open('../Pics/image.png').convert('L'))
background = np.array(Image.open('../Pics/background.JPG').convert('L'))
img_filtered = img - background
What could you advise me ? The ideal would be to stay in RGB, though I don't know almost anything about image processing, filters, etc ...
By "the result is pretty ... (really) bad", i assume, you see a picture like this:
This seems to be due to the fact, that subtracting images, which could produce negative numbers instead starts "from the top" of the brightness-scale, like this:
4-5 = 255 instead of -1.
This is a byproduct, on how the pictures are loaded.
If i use "plain numpy array", get a picture like this:
So maybe try handling your pictures as numpy arrays: take a look over here
[Edit: This is due to the dtype uint8 of the numpy arrays. Changing to int should already be enough]

read an array of pixel values python

I would like to take a screenshot with a certain range of the screen, and then I would like to check the pixel values of certain lines (eg x_axis from 400 to 800).
I tried multiple ways like the imagegrab, gdi32.GetPixel and some more. It seems reading pixels values take a lot of time, so I even tried converting it into a list, something like this
im = ImageGrab.grab(box)
pixels = list(im .getdata())
Even this does not seem fast. Is there something I'm doing wrong?
ImageGrab returns pixels in PIL format (the Python Imaging Library: http://effbot.org/imagingbook/image.htm), and .getdata() already returns the pixels as a sequence. By wrapping it in list() again you are doing the same (expensive) operation twice. You can just do:
im = ImageGrab.grab(box)
pixels = im.getdata()
And iterate through your pixels in your favorite way.

Using PyAutoGUI to locate an image on screen regardless of the color tone / brightness

I'm looking for a simple way in Python (PyAutoGUI) to locate all the images of a certain type on the screen but here's the catch, each image has a different gradient / color tone and I don't want to take the screen shot of each and every image to locate them on screen.
Here's the region of the screen containing the images I am trying to get the coordinates of:
As you can see every square has a unique color (the contrast).
So I want to get the coordinate of every square making PyAutoGUI scan just one image. Is there any way I could make it ignore the difference in contrast of the images? Like making it black and white mode or something.
How the code works:
import pyautogui
coordinates = pyautogui.locateAllOnScreen("image.png") # Returns list of coordinates of all images matching image.png
I know this is 2 years old but for any future humans that find this like me try the confidence argument.
import pyautogui
button7location = pyautogui.locateOnScreen('calc7key.png', confidence=0.9)
button7location
Box(left=1416, top=562, width=50, height=41)
Source: https://pyautogui.readthedocs.io/en/latest/screenshot.html#the-locate-functions
I would try the following:
pyautogui.locateOnScreen("image.png", grayscale=True)
Which will ignore color values and simply compaire the contrast of values. This has the added benefit of comparing about 30% quicker but can lead to false positives.

Categories

Resources