python face detection raspberry pi with picamera - python

I am a newbie with python and opencv i am trying to build a face detection project with raspberry pi. i am getting this error and here is my code
Traceback (most recent call last):
File "/home/pi/Desktop/picamera-code/FaceDetection1.0", line 19, in <module>
for frame in
camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
Code:
import numpy as np
import cv2
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
camera = PiCamera()
camera.resolution = (640, 480)
camera.framerate = 32
rawCapture = PiRGBArray(camera, size=(640, 480))
time.sleep(0.1)
face_cascade = cv2.CascadeClassifier('/home/pi/Downloads/haarcascade_frontalface_default.xml')
for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
img=np.asarray(frame.array)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
img = cv2.Rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

The problem is in your camera.capture_continuos. First value, output, cannot be just an array as it records with an infinite iteration as the docs says. Instead of this you should put an output file. If you want an stream to capture this you can use the io.Bytes as well.
In this link it explains you examples on how tu use the frame and where should you redirect the output.
You can do something like what suggest on the API docs. Take the stream and truncate it to get the image that you are currently getting:
import io
import time
import picamera
with picamera.PiCamera() as camera:
stream = io.BytesIO()
for foo in camera.capture_continuous(stream, format='jpeg'):
# YOURS: for frame in camera.capture_continuous(stream, format="bgr", use_video_port=True):
# Truncate the stream to the current position (in case
# prior iterations output a longer image)
stream.truncate()
stream.seek(0)
if process(stream):
break

The correct answer is that you need to truncate the stream at the end of the loop. Add
rawCapture.truncate(0)
at the end of the first for loop.

if you change the part in line 11 640, 420 to 160, 120 it should work

Related

How to read grayscale img from a video with OpenCV?

I read all pictures from my pic directory and then convert them each to gray-scale with canny edge detections before writing it all to a video.
But, when I use my video software to play it, it shows a green background, and I can't read video frames from it. Could someone show me how to solve it?
Sample code
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
fourcc = cv.VideoWriter_fourcc(*"I420")
out = cv.VideoWriter("t2.avi", fourcc, 1, (640, 480), 0)
for pic in glob.glob1("./pic/", "A*"):
img = cv.imread(f"./pic/{pic}", -1)
edge = cv.Canny(img, 100, 200)
edge = cv.resize(edge, (640, 480))
out.write(edge)
out.release()
# Cant read video frame here:
cap = cv.VideoCapture("t2.avi")
ret, frame = cap.read()
if ret:
plt.imshow(frame)
else:
print("end")
cap.release()
Video plays with green background
It looks like a compatibility issue between I420 FOURCC and Grayscale format.
Replace fourcc = cv.VideoWriter_fourcc(*"I420") with:
fourcc = cv.VideoWriter_fourcc(*"GREY")
Note:
I am using OpenCV 4.5.5 in Windows 10, and it's working with "GREY".
I am not sure it's going to work in all platforms and versions.
I420 applies colored video.
You may use I420 with colored video:
Replace out = cv.VideoWriter("t2.avi", fourcc, 1, (640, 480), 0) with:
out = cv.VideoWriter("t2.avi", fourcc, 1, (640, 480), 1)
Convert edge to BGR before writing:
edge = cv.cvtColor(edge, cv.COLOR_GRAY2BGR)
out.write(edge)
Code sample using "GREY" FOURCC:
import numpy as np
import cv2 as cv
#import matplotlib.pyplot as plt
import glob
#fourcc = cv.VideoWriter_fourcc(*"I420")
fourcc = cv.VideoWriter_fourcc(*"GREY")
out = cv.VideoWriter("t2.avi", fourcc, 1, (640, 480), 0)
for pic in glob.glob1("./pic/", "A*"):
img = cv.imread(f"./pic/{pic}", -1)
edge = cv.Canny(img, 100, 200)
edge = cv.resize(edge, (640, 480))
out.write(edge)
out.release()
# Cant read video frame here:
cap = cv.VideoCapture("t2.avi")
while True:
ret, frame = cap.read()
if ret:
#plt.imshow(frame)
cv.imshow('frame', frame)
cv.waitKey(1000)
else:
print("end")
cap.release()
break
cv.destroyAllWindows()

How can I achieve a 30 FPS frame rate using this Python screen recorder code?

I want a screen recorder. I thought of making my own.
I checked the internet and found: https://www.thepythoncode.com/code/make-screen-recorder-python
The Code:
import cv2
import numpy as np
import pyautogui
# Display screen resolution, get it from your OS settings
SCREEN_SIZE = (1366, 768)
# Define the codec
fourcc = cv2.VideoWriter_fourcc(*"XVID")
# Create the video write object
out = cv2.VideoWriter("output.avi", fourcc, 30.0, (SCREEN_SIZE))
while True:
# make a screenshot
img = pyautogui.screenshot()
# img = pyautogui.screenshot(region=(0, 0, 300, 400))
# convert these pixels to a proper numpy array to work with OpenCV
frame = np.array(img)
# convert colors from BGR to RGB
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# write the frame
out.write(frame)
# show the frame
cv2.imshow("screenshot", frame)
# if the user clicks q, it exits
if cv2.waitKey(1) == ord("q"):
break
# Make sure everything is closed when exited
cv2.destroyAllWindows()
out.release()
The Problem:
When I run this, this works good. But it has a random speed after output. The fps is 30 but when I record for 1 minute, the video is 5 seconds or 10 minutes (random).
How do I make this recorder give output in 30 fps with the correct speed?
basically if you want to continue with your same code, you will have to compromise on resolution or frame rate.
My suggestion is to try the cv2.VideoCapture() functionality.
I am attaching the link to the webpage where there is a detailed step-by-step process where the author has achieved an FPS rate of 30.75.
Here's the link:
https://www.pyimagesearch.com/2017/02/06/faster-video-file-fps-with-cv2-videocapture-and-opencv/
The second half of the content present in the link has The faster, threaded method to reading video frames with OpenCV.
# import the necessary packages
from imutils.video import FileVideoStream
from imutils.video import FPS
import numpy as np
import argparse
import imutils
import time
import cv2
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video", required=True,
help="path to input video file")
args = vars(ap.parse_args())
# start the file video stream thread and allow the buffer to
# start to fill
print("[INFO] starting video file thread...")
fvs = FileVideoStream(args["video"]).start()
time.sleep(1.0)
# start the FPS timer
fps = FPS().start()
# loop over frames from the video file stream
while fvs.more():
# grab the frame from the threaded video file stream, resize
# it, and convert it to grayscale (while still retaining 3
# channels)
frame = fvs.read()
frame = imutils.resize(frame, width=450)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame = np.dstack([frame, frame, frame])
# display the size of the queue on the frame
cv2.putText(frame, "Queue Size: {}".format(fvs.Q.qsize()),
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
# show the frame and update the FPS counter
cv2.imshow("Frame", frame)
cv2.waitKey(1)
fps.update()
# stop the timer and display FPS information
fps.stop()
print("[INFO] elasped time: {:.2f}".format(fps.elapsed()))
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))
# do a bit of cleanup
cv2.destroyAllWindows()
fvs.stop()

my print("Found faces", str(len(faces))) not executed

I'm trying to detect multiple faces using opencv in python. I'm doing this in raspbian OS (raspberry Pi 3). Although the code is working properly, i.e, it's detecting a face and drawing a rectangular boundary around the face. It successfully saves the image in my local folder as well. The problem is : the statement print("Found faces", str(len(faces))) isn't working and the console remains blank. What am I missing here or where am I going wrong?
import io
import picamera
import cv2
import numpy
stream = io.BytesIO()
with picamera.PiCamera() as camera:
camera.resolution = (320, 240)
camera.hflip = True
camera.capture(stream, format='jpeg')
buff = numpy.fromstring(stream.getvalue(), dtype=numpy.uint8)
image = cv2.imdecode(buff, 1)
face_cascade = cv2.CascadeClassifier('face1.xml')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.1, 5)
print("Found faces", str(len(faces)))
for (x,y,w,h) in faces:
cv2.rectangle(image,(x,y),(x+w,y+h),(255,255,0),2)
cv2.imwrite('result.jpg',image)

Opencv raspicam

Hi I would like to run this code to detect cars using raspicam on a raspberry pi B with OpenCV but encountered errors.
import numpy as np
import cv2
car_cascade = cv2.CascadeClassifier('cars3.xml')
cap = cv2.VideoCapture(0)
while 1:
ret, img = cap.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cars = car_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in cars:
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
cv2.imshow('img',img)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release()
cv2.destroyAllWindows()
After running the code it returns
OpenCV Error: Assertion failed (scn == 3 || scn == 4) in cvtColor, file /home/pi/installopencv/opencv-3.1.0/modules/imgproc/src/color.cpp, line 8000
Traceback (most recent call last):
File "test.py", line 14, in <module>
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.error: /home/pi/installopencv/opencv-3.1.0/modules/imgproc/src/color.cpp:8000: error: (-215) scn == 3 || scn == 4 in function cvtColor
Is the error happening because I'm using raspicam and "cap = cv2.VideoCapture(0)" only work for webcam? I trying enabling V4L2 module but it didn't work as well
If you want to use the Raspberry PI camera module, use the picamera module to get the frames, not OpenCV'2 videoCapture module. In particular you want to install module with array support:
pip install "picamera[array]"
This will allow you to easily pass the frames to OpenCV.
There's a very good tutorial on how start from scratch here
and here is the gist of it:
# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2
# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (640, 480)
camera.framerate = 32
rawCapture = PiRGBArray(camera, size=(640, 480))
# allow the camera to warmup
time.sleep(0.1)
# capture frames from the camera
for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
# grab the raw NumPy array representing the image, then initialize the timestamp
# and occupied/unoccupied text
image = frame.array
# show the frame
cv2.imshow("Frame", image)
key = cv2.waitKey(1) & 0xFF
# clear the stream in preparation for the next frame
rawCapture.truncate(0)
# if the `q` key was pressed, break from the loop
if key == ord("q"):
break
In your case, you may want to change the format from "rgb" to "yuv".
This way, you can extract the y(luminosity) channel directly which will be your grayscale method. Hopefully you'll gain a small boost in speed not having to do the colourspace conversion (from BGR to grayscale) and fetching the frames from CSI (instead of USB).

Superimposing image over webcam feed using OpenCV 2.4.7.0 in Python 2.7

I am trying to superimpose an image over a camera feed in python. I can get an image to superimpose over another image, but when I apply the same thing to my camera feed it doesn't work. Here's my code so far:
#!/usr/bin/python
import cv2
import time
cv2.cv.NamedWindow("Hawk Eye", 1)
capture = cv2.cv.CaptureFromCAM(0)
cv2.cv.SetCaptureProperty(capture, cv2.cv.CV_CAP_PROP_FRAME_WIDTH, 800)
cv2.cv.SetCaptureProperty(capture, cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, 600)
x_offset=y_offset=50
arrows = cv2.imread("arrows.png")
while True:
webcam=cv2.cv.QueryFrame(capture)
#webcam[y_offset:y_offset+arrows.shape[0], x_offset:x_offset+arrows.shape[1]]=arrows
cv2.cv.ShowImage("Hawk Eye", webcam)
if cv2.cv.WaitKey(10) == 27:
break
cv2.cv.DestroyAllWindows()
If I uncomment:
img[y_offset:y_offset+arrows.shape[0], x_offset:x_offset+arrows.shape[1]]=arrows
the line that imposes the image, it shows just the camera feed, but when I add it in my loop it stops working. Thanks!
This works OK using the cv2 API:
import cv2
import time
cv2.namedWindow("Hawk Eye", 1)
capture = cv2.VideoCapture(0)
capture.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, 800)
capture.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, 600)
x_offset=y_offset=50
arrows = cv2.imread("hawk.png")
while True:
ret, webcam = capture.read()
if ret:
webcam[y_offset:y_offset+arrows.shape[0], x_offset:x_offset+arrows.shape[1]]=arrows
cv2.imshow("Hawk Eye", webcam)
if cv2.waitKey(10) == 27:
break
cv2.destroyAllWindows()

Categories