we are using a Raspberry Pi + Python 3.4 + PyGame to capture an image from a specific USB webcam. We use this simple code to capture (it works ok):
pygame.camera.init()
cam = pygame.camera.Camera(pygame.camera.list_cameras()[0],(1280,720))
cam.start()
time.sleep(1)
webcamImage = cam.get_image()
The problem comes here: we have to convert this webcamImage into a PIL image. We follow this link but unfortunately the function Image.fromstring() not exists anymore. So, we can't do that:
pil_string_image = pygame.image.tostring(webcamImage, "RGBA",False)
pil_image = Image.fromstring("RGBA",(1280,720),pil_string_image)
PIL says that Image.fromstring() is deprecated, and suggests to use the function Image.frombytes(). Clearly we not found the equivalent pygame.image function that convert the webcamImage into an array of bytes. So we are stucked here: can you help us, please?
Thank you :-)
As per Damian Yerrick's comment, under Python 3 the result of pygame.image.tostring() is a bytes, despite the method's name. Thus we can go out of this situation with this simple code:
pygame.camera.init()
cam = pygame.camera.Camera(pygame.camera.list_cameras()[0],(1280,720))
cam.start()
time.sleep(1)
webcamImage = cam.get_image()
pil_string_image = pygame.image.tostring(webcamImage,"RGBA",False)
im = Image.frombytes("RGBA",(1280,720),pil_string_image)
Related
Getting the error bellow in the code
TypeError: 'NoneType' object is not subscriptable
line : crop_img = img[70:300, 70:300]
Can anyone please help me with this?
thanks a lot
img_dofh = cv2.imread("D.png",0)
ret, img = cap.read()
cv2.rectangle(img,(60,60),(300,300),(255,255,2),4) #outer most rectangle
crop_img = img[70:300, 70:300]
crop_img_2 = img[70:300, 70:300]
grey = cv2.cvtColor(crop_img, cv2.COLOR_BGR2GRAY)
You don't show where your img variable comes from. But somehow it is None instead of containing image data.
Often this happens when you write a function that is supposed to return a valid object for img, but you forget to include a return statement in the function, so it automatically returns None instead.
Check the code that creates img.
UPDATE
Responding to your code posting:
It would be helpful if you could provide a minimal, reproducible example. That might look something like this:
import cv2
cap = cv2.VideoCapture(0)
if cap.isOpened():
ret, img = cap.read()
if img is None:
print("img was not returned.")
else:
crop_img = img[70:300, 70:300]
print(crop_img) # should show an array of image data
Looking at the documentation, it appears that your camera may not have grabbed any frames by the time you reach this point in your code. The documentation says "If no frames has been grabbed (camera has been disconnected, or there are no more frames in video file), the methods return false and the functions return NULL pointer." I would bet that the .read() function is returning a NULL pointer, which gets converted to None when it is sent back to Python.
Unfortunately, since no one else has your particular camera setup, other people may have trouble reproducing your problem.
The code above works fine on my MacBook Pro, but I have to give Terminal permission to use the camera the first time I try it. Have you tried restarting your terminal app? Does your program have access to the camera?
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)
I've showed in various ways how to take images with a webcam in Python (see How can I take camera images with Python?). You can see that the images taken with Python are considerably darker than images taken with JavaScript. What is wrong?
Image example
The image on the left was taken with http://martin-thoma.com/html5/webcam/, the one on the right with the following Python code. Both were taken with the same (controlled) lightning situation (it was dark outside and I only had some electrical lights on) and the same webcam.
Code example
import cv2
camera_port = 0
camera = cv2.VideoCapture(camera_port)
return_value, image = camera.read()
cv2.imwrite("opencv.png", image)
del(camera) # so that others can use the camera as soon as possible
Question
Why is the image taken with Python image considerably darker than the one taken with JavaScript and how do I fix it?
(Getting a similar image quality; simply making it brighter will probably not fix it.)
Note to the "how do I fix it": It does not need to be opencv. If you know a possibility to take webcam images with Python with another package (or without a package) that is also ok.
Faced the same problem. I tried this and it works.
import cv2
camera_port = 0
ramp_frames = 30
camera = cv2.VideoCapture(camera_port)
def get_image():
retval, im = camera.read()
return im
for i in xrange(ramp_frames):
temp = camera.read()
camera_capture = get_image()
filename = "image.jpg"
cv2.imwrite(filename,camera_capture)
del(camera)
I think it's about adjusting the camera to light. The former
former and later images
I think that you have to wait for the camera to be ready.
This code works for me:
from SimpleCV import Camera
import time
cam = Camera()
time.sleep(3)
img = cam.getImage()
img.save("simplecv.png")
I took the idea from this answer and this is the most convincing explanation I found:
The first few frames are dark on some devices because it's the first
frame after initializing the camera and it may be required to pull a
few frames so that the camera has time to adjust brightness
automatically.
reference
So IMHO in order to be sure about the quality of the image, regardless of the programming language, at the startup of a camera device is necessary to wait a few seconds and/or discard a few frames before taking an image.
Tidying up Keerthana's answer results in my code looking like this
import cv2
import time
def main():
capture = capture_write()
def capture_write(filename="image.jpeg", port=0, ramp_frames=30, x=1280, y=720):
camera = cv2.VideoCapture(port)
# Set Resolution
camera.set(3, x)
camera.set(4, y)
# Adjust camera lighting
for i in range(ramp_frames):
temp = camera.read()
retval, im = camera.read()
cv2.imwrite(filename,im)
del(camera)
return True
if __name__ == '__main__':
main()
I just want to display python image object in wxpython panel.
What i am trying to accomplish is taking screenshot using python ImageGrab or autopy and showing it in wxpython panel. My screenshot program running every second so there is no point save the image for wx.
import pyscreenshot as ImageGrab
imgobj = ImageGrab.grab()
print imgobj
# Convert into wximage
myWxImage = wx.EmptyImage( imgobj.size[0], imgobj.size[0] )
myWxImage.SetData( imgobj.convert( 'RGB' ).tostring())
Output
<Image.Image image mode=RGB size=1366x768 at 0x20B98F0>
ValueError:Invalid data buffer size.
It's not easy to tell without a full traceback, but I think the issue might be this typo:
myWxImage = wx.EmptyImage( imgobj.size[0], imgobj.size[0] )
Should be:
myWxImage = wx.EmptyImage( imgobj.size[0], imgobj.size[1] )
Also you could make your code simpler with:
myWxImage = wx.ImageFromBuffer(imgobj.size[0], imgobj.size[1], imgobj.convert('RGB').tostring())
I assume your problem is that you are passing the image width as new height to wx...
And btw instead you could use
myWxImage = wx.ImageFromBuffer( imgobj.size[0], imgobj.size[1], imgobj.tostring() )
What imaging modules for python will allow you to take a specific size screenshot (not whole screen)?
I have tried PIL, but can't seem to make ImageGrab.grab() select a small rectangle
and i have tried PyGame but i can't make it take a screen shot outside of it's main display panel
You can use pyscreenshot module.
The pyscreenshot module can be used to copy the contents of the screen to a PIL image memory or file.
You can install it using pip.
$ sudo pip install pyscreenshot
Usage:
import pyscreenshot as ImageGrab
# fullscreen
im=ImageGrab.grab()
im.show()
# part of the screen
im=ImageGrab.grab(bbox=(10,10,500,500))
im.show()
# to file
ImageGrab.grab_to_file('im.png')
I have tried PIL, but can't seem to make ImageGrab.grab() select a small rectangle
What did you try?
As the documentation for ImageGrab clearly states, the function has a bbox parameter, and:
The pixels inside the bounding box are returned as an “RGB” image. If the bounding box is omitted, the entire screen is copied.
So, you only get the whole screen if you don't pass a bbox.
Note that, although I linked to the Pillow docs (and you should be using Pillow), old-school PIL's docs say the same thing:
The bounding box argument can be used to copy only a part of the screen.
So, unless you're using a really, really old version of PIL (before 1.1.3, which I believe is more than a decade out of date), it has this feature.
1) Use pyscreenshot, ImageGrab works but only on Windows
2) Grab the image and box it, then save that image
3) Don't use ImageGrab.grab_to_file, it saves the full size image
4) You don't need to show the image with im.show if you just want to save a screenshot
import pyscreenshot as ImageGrab
im=ImageGrab.grab(bbox=(10,10,500,500))
im.save('im.png')
You could use Python MSS.
From documentation to capture only a part of the screen:
import mss
import mss.tools
with mss.mss() as sct:
# The screen part to capture
monitor = {"top": 160, "left": 160, "width": 160, "height": 135}
output = "sct-{top}x{left}_{width}x{height}.png".format(**monitor)
# Grab the data
sct_img = sct.grab(monitor)
# Save to the picture file
mss.tools.to_png(sct_img.rgb, sct_img.size, output=output)
print(output)
You can use pyscreenshot at linux or windows platforms . I am using Ubuntu it works for me. You can force if subprocess is applied setting it to false together with mss gives the best performance.
import pyscreenshot as ImageGrab
import time
t1 = time.time()
imgScreen = ImageGrab.grab(backend="mss", childprocess=False)
img = imgScreen.resize((640,480))
img.save("screen.png")
t2 = time.time()
print("The passing time",(t2-t1))