python pygame blit. Getting an image to display - python

I'm trying to get my webcam to show video through pygame. Here is the code:
# import the relevant libraries
import time
import pygame
import pygame.camera
from pygame.locals import *
# this is where one sets how long the script
# sleeps for, between frames.sleeptime__in_seconds = 0.05
# initialise the display window
pygame.init()
pygame.camera.init()
screen = pygame.display.set_mode((640, 480), 0, 32)
# set up a camera object
cam = pygame.camera.Camera(0)
# start the camera
cam.start()
while 1:
# sleep between every frame
time.sleep( 10 )
# fetch the camera image
image = cam.get_image()
# blank out the screen
screen.fill((0,0,2))
# copy the camera image to the screen
screen.blit( image, ( 0, 0 ) )
# update the screen to show the latest screen image
pygame.display.update()
When i try this I get an error from the screen.blit( image, ( 0, 0 ) ) part
Traceback (most recent call last):
File "C:\Python32\src\webcam.py", line 28, in <module>
screen.blit( image, ( 0, 0 ) )
TypeError: argument 1 must be pygame.Surface, not None
I assume It's because I didn't convert the image into whatever works with pygame, but i don't know.
Any help would be appreciated.Thanks.
-Alex
OK so here is the new code:
This one works because it saves the picture to the current folder. figured out why the last one work. the screen is still black although=\
# import the relevant libraries
import time
import pygame
import pygame.camera
from pygame.locals import *
# this is where one sets how long the script
# sleeps for, between frames.sleeptime__in_seconds = 0.05
# initialise the display window
pygame.init()
pygame.camera.init()
# set up a camera object
size = (640,480)
screen = pygame.display.set_mode(size,0)
surface = pygame.surface.Surface(size,0,screen)
cam = pygame.camera.Camera(0,size)
# start the camera
cam.start()
while 1:
# sleep between every frame
time.sleep( 10 )
# fetch the camera image
pic = cam.get_image(surface)
# blank out the screen
#screen.fill((0,0,0))
# copy the camera image to the screen
screen.blit(pic,(0,0))
# update the screen to show the latest screen image
p=("outimage.jpg")
pygame.image.save(surface,p)
pygame.display.update()

Try creating a Camera like this.
cam = pygame.camera.Camera(camlist[0],(640,480))
That's how it's done on this page of the pygame docs.
Looking at the API page for pygame.camera, I found two things that might help. First,
Pygame currently supports only Linux and v4l2 cameras.
EXPERIMENTAL!: This api may change or disappear in later pygame
releases. If you use this, your code will very likely break with the
next pygame release.
Keep that in mind when wondering why this surprisingly fails.
On a more up-beat note... you can try calling camera.get_raw() and printing the result. It should be a string with raw image data. If you get an empty string, None, or some non-sense text: please share that with us here. It'll tell if you're getting anything from the camera.
Gets an image from a camera as a string in the native pixelformat of the camera. Useful for integration with other libraries.

Related

Pygame cam.get_raw() returns None

I'm fairly new to useing pygame and I'm trying to take a picture from the webcam and saving it as a png file. This is my code:
import pygame
import pygame.camera
from pygame.locals import *
pygame.init()
pygame.camera.init()
cam = pygame.camera.Camera('Integrated Webcam',(640,480))
cam.start()
image = cam.get_image()
pygame.image.save(image, 'test.png')
print(cam.get_raw())
This prints out None and the png file that it creates is completely black
Problem is solved, needed to pause for about .65 seconds to give time for the camera to power on.

take full screenshot python

I am trying to take a screenshot for my screen(s).
I am aware of the function
pyautogui.screenshot()
The problem with this function is that it can take a screenshot for one screen only. I am trying to take a full screenshot for all available screens (typically two). But, it does not seem to work in this regards.
Given the fact that you want to use a Windows system I would like to suggest you to use Desktopmagic, a Python Library.
Here's an example:
from __future__ import print_function
from desktopmagic.screengrab_win32 import (
getDisplayRects, saveScreenToBmp, saveRectToBmp, getScreenAsImage,
getRectAsImage, getDisplaysAsImages)
# Save the entire virtual screen as a BMP (no PIL required)
saveScreenToBmp('screencapture_entire.bmp')
# Save an arbitrary rectangle of the virtual screen as a BMP (no PIL required)
saveRectToBmp('screencapture_256_256.bmp', rect=(0, 0, 256, 256))
# Save the entire virtual screen as a PNG
entireScreen = getScreenAsImage()
entireScreen.save('screencapture_entire.png', format='png')
# Get bounding rectangles for all displays, in display order
print("Display rects are:", getDisplayRects())
# -> something like [(0, 0, 1280, 1024), (-1280, 0, 0, 1024), (1280, -176, 3200, 1024)]
# Capture an arbitrary rectangle of the virtual screen: (left, top, right, bottom)
rect256 = getRectAsImage((0, 0, 256, 256))
rect256.save('screencapture_256_256.png', format='png')
# Unsynchronized capture, one display at a time.
# If you need all displays, use getDisplaysAsImages() instead.
for displayNumber, rect in enumerate(getDisplayRects(), 1):
imDisplay = getRectAsImage(rect)
imDisplay.save('screencapture_unsync_display_%d.png' % (displayNumber,), format='png')
# Synchronized capture, entire virtual screen at once, cropped to one Image per display.
for displayNumber, im in enumerate(getDisplaysAsImages(), 1):
im.save('screencapture_sync_display_%d.png' % (displayNumber,), format='png')
I would suggest another module if you mind: MSS (you do not need PIL or any other module, just Python; and it is cross-platform):
from mss import mss
with mss() as sct:
sct.shot(mon=-1, output="fullscreen.png")
The documentation tries to explain more things, if you are interested.
Using pyscreenshot library worked for me, I took a screenshot of all screens.
Source: https://pypi.org/project/pyscreenshot/
#-- include('examples/showgrabfullscreen.py') --#
import pyscreenshot as ImageGrab
if __name__ == '__main__':
# grab fullscreen
im = ImageGrab.grab()
# save image file
im.save('screenshot.png')
# show image in a window
im.show()
#-#
If you don't want to open the GUI, just comment the im.show() line.

pygame with FULLSCREEN flag renders content scaled

I'm using pygame on a raspberry pi.
This same code used to cover the full screen at 800x600, now, at 1280x720 it doesn't, and it's not over/underscan:
Pygame example output:
Video playback via omxplayer:
All the code in the pygame example image is just a demo for the problem:
import pygame
import time
pygame.display.init()
pygame.font.init()
screen = pygame.display.set_mode((1280, 720)) #, pygame.FULLSCREEN)
screen.fill((255, 0, 0))
pygame.display.flip()
time.sleep(45)
You can use the list_modes function which returns a list of available full screen resolutions:
modes = pygame.display.list_modes()
if modes: # check if the list is not empty
screen = pygame.display.set_mode(modes[0], pygame.FULLSCREEN) # use the first one
else:
screen = pygame.display.set_mode((800, 600)) # use a default resolution
Note: if you have problems with high DPI scaling on Windows (e. g. a part of your display is not visible), you can use this code to fix them:
import ctypes
ctypes.windll.shcore.SetProcessDpiAwareness(1)

How to display a loaded image on a pygame.Overlay()

I am trying to use overlays in pygame to display video. The trouble is that my frames are loaded as RGB Surface()s while Overlay().display() requires YUV format.
I saw that pygame.camera module contains a colorspace() function that should be able to convert RGB Surface() to YUV one. Does anyone know how to do the trick? The conversion and the displaying?
pygame.camera.colorspace() is not very well documented.
If this doesn't work, does anyone know how to do this by using PIL to convert to YUV?
I haven't had much time to play with .Overlay()
but the colorspace function seems to go as follows:
yuv_surface = pygame.camera.colorspace(rgb_surface,"YUV")
This example runs without error:
import pygame
import pygame.camera
pygame.init()
pygame.camera.init()
screen = pygame.display.set_mode((400,400))
rgb_surface = pygame.Surface((400,400))
yuv_surface = pygame.camera.colorspace(rgb_surface,"YUV")
screen.blit(yuv_surface,(0,0))
clock = pygame.time.Clock()
while True:
pygame.display.flip()
clock.tick(30)

display cv2.VideoCapture image inside Pygame surface

I'm trying to use opencv (cv2) to stream a webcam feed into a pygame surface object. The problem is the colors aren't displaying correctly. I think it is the type casting, but I'm having trouble understanding the pygame surface documentation to know what it expects.
This code demonstrates what I'm talking about
import pygame
from pygame.locals import *
import cv2
import numpy
color=False#True#False
camera_index = 0
camera=cv2.VideoCapture(camera_index)
camera.set(3,640)
camera.set(4,480)
#This shows an image the way it should be
cv2.namedWindow("w1",cv2.CV_WINDOW_AUTOSIZE)
retval,frame=camera.read()
if not color:
frame=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
cv2.flip(frame,1,frame)#mirror the image
cv2.imshow("w1",frame)
#This shows an image weirdly...
screen_width, screen_height = 640, 480
screen=pygame.display.set_mode((screen_width,screen_height))
def getCamFrame(color,camera):
retval,frame=camera.read()
if not color:
frame=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
frame=numpy.rot90(frame)
frame=pygame.surfarray.make_surface(frame) #I think the color error lies in this line?
return frame
def blitCamFrame(frame,screen):
screen.blit(frame,(0,0))
return screen
screen.fill(0) #set pygame screen to black
frame=getCamFrame(color,camera)
screen=blitCamFrame(frame,screen)
pygame.display.flip()
running=True
while running:
for event in pygame.event.get(): #process events since last loop cycle
if event.type == KEYDOWN:
running=False
pygame.quit()
cv2.destroyAllWindows()
The ultimate goal I have is to create a small photo booth application for a DIY wedding next year. I'm new to programming, but I've managed to cobble this together. I was also trying to accomplish this with VideoCapture, which outputs a PIL, which I also couldn't get to work with the surface object. I want to use a pygame surface so I can animate and overlay count-down text, borders, etc.
Update: The issue was that the cv2 function camera.read() returns a BGR image, but the pygame.surfarray expects a RGB image. This is fixed with the line
frame=cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
Also, when converting to grayscale, the following code works:
frame=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
frame=cv2.cvtColor(frame,cv2.COLOR_GRAY2RGB)
So, the function getCamFrame should now be
def getCamFrame(color,camera):
retval,frame=camera.read()
frame=cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
if not color:
frame=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
frame=cv2.cvtColor(frame,cv2.COLOR_GRAY2RGB)
frame=numpy.rot90(frame)
frame=pygame.surfarray.make_surface(frame)
return frame
No the color error lies in here
frame=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
so for normal screen color u simply change that to
frame=cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
That will do because it works for me
I tried your code, but I'm only getting a picture not a movie, so i copied
frame=getCamFrame(color,camera)
screen=blitCamFrame(frame,screen)
pygame.display.flip()
into a while loop, it worked but then the video was flipped, to fix it i added cv2.flip(frame,1,frame) # mirror the image
before
frame=numpy.rot90(frame) in getcamFrame function and now everything works fine.
Sorry for the poor English.
This worked for me
to adapt it in your code ...
windowSurface = screen #or use directly variable screen
# convert windowSurface to cv2 ------------------------------------
view = pygame.surfarray.array3d(windowSurface)
# convert from (width, height, channel) to (height, width, channel)
view = view.transpose([1, 0, 2])
# convert from rgb to bgr
img_bgr = cv2.cvtColor(view, cv2.COLOR_RGB2BGR)
cv2.imshow('windowname',img_bgr)
cv2.waitKey(10)

Categories

Resources