my picam to raspberry pi 3 for face detection but i am getting this error - python-3.5

gray = cv2.cvtColor(image_frame, cv2.COLOR_BGR2GRAY) cv2.error: /home/pi/Downloads/opencv/modules/imgproc/src/color.cpp:11095: error: (-215) scn == 3 || scn == 4 in function cvtColor.
Is there anyway to solve it without changing the picam?
# Import OpenCV2 for image processing
import cv2
# Start capturing video
vid_cam = cv2.VideoCapture(0)
# Detect object in video stream using Haarcascade Frontal Face
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# For each person, one face id
face_id = 5
# Initialize sample face image
count = 0
# Start looping
while(True):
# Capture video frame
_, image_frame = vid_cam.read()
# Convert frame to grayscale
gray = cv2.cvtColor(image_frame, cv2.COLOR_BGR2GRAY)
# Detect frames of different sizes, list of faces rectangles
faces = face_detector.detectMultiScale(gray, 1.3, 5)
# Loops for each faces
for (x,y,w,h) in faces:
# Crop the image frame into rectangle
cv2.rectangle(image_frame, (x,y), (x+w,y+h), (255,0,0), 2)
# Increment sample face image
count += 1
# Save the captured image into the datasets folder
cv2.imwrite("dataset/User." + str(face_id) + '.' + str(count) + ".jpg", gray[y:y+h,x:x+w])
# Display the video frame, with bounded rectangle on the person's face
cv2.imshow('frame', image_frame)
# To stop taking video, press 'q' for at least 100ms
if cv2.waitKey(100) & 0xFF == ord('q'):
break
# If image taken reach 100, stop taking video
elif count>100:
break
# Stop video
vid_cam.release()
# Close all started windows
cv2.destroyAllWindows()code here

If you are using picam,
then you have to import the picam module
import picamera
def getFrame():
jpegBuffer = io.BytesIO()
webcam.capture(jpegBuffer, format='jpeg')
buff = numpy.fromstring(jpegBuffer.getvalue(), dtype=numpy.uint8)
return cv2.imdecode(buff, 1)
image_frame = getFrame()
try this once,

Related

How to find the location of a point in an image in millimeters using camera matrix?

I am using a standard 640x480 webcam. I have done Camera calibration in OpenCV in Python 3. This the Code I am using. The code is working and giving me the Camera Matrix and Distortion Coefficients successfully.
Now, How can I find how many millimeters are there in 640 pixels in my scene image. I have attached the webcam above a table horizontally and on the table, a Robotic arm is placed. Using the camera I am finding the centroid of an object. Using Camera Matrix my goal is to convert the location of that object (e.g. 300x200 pixels) to the millimeter units so that I can give the millimeters to the robotic arm to pick that object.
I have searched but not find any relevant information.
Please tell me that is there any equation or method for that. Thanks a lot!
import numpy as np
import cv2
import yaml
import os
# Parameters
#TODO : Read from file
n_row=4 #Checkerboard Rows
n_col=6 #Checkerboard Columns
n_min_img = 10 # number of images needed for calibration
square_size = 40 # size of each individual box on Checkerboard in mm
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) # termination criteria
corner_accuracy = (11,11)
result_file = "./calibration.yaml" # Output file having camera matrix
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(n_row-1,n_col-1,0)
objp = np.zeros((n_row*n_col,3), np.float32)
objp[:,:2] = np.mgrid[0:n_row,0:n_col].T.reshape(-1,2) * square_size
# Intialize camera and window
camera = cv2.VideoCapture(0) #Supposed to be the only camera
if not camera.isOpened():
print("Camera not found!")
quit()
width = int(camera.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(camera.get(cv2.CAP_PROP_FRAME_HEIGHT))
cv2.namedWindow("Calibration")
# Usage
def usage():
print("Press on displayed window : \n")
print("[space] : take picture")
print("[c] : compute calibration")
print("[r] : reset program")
print("[ESC] : quit")
usage()
Initialization = True
while True:
if Initialization:
print("Initialize data structures ..")
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.
n_img = 0
Initialization = False
tot_error=0
# Read from camera and display on windows
ret, img = camera.read()
cv2.imshow("Calibration", img)
if not ret:
print("Cannot read camera frame, exit from program!")
camera.release()
cv2.destroyAllWindows()
break
# Wait for instruction
k = cv2.waitKey(50)
# SPACE pressed to take picture
if k%256 == 32:
print("Adding image for calibration...")
imgGray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# Find the chess board corners
ret, corners = cv2.findChessboardCorners(imgGray, (n_row,n_col),None)
# If found, add object points, image points (after refining them)
if not ret:
print("Cannot found Chessboard corners!")
else:
print("Chessboard corners successfully found.")
objpoints.append(objp)
n_img +=1
corners2 = cv2.cornerSubPix(imgGray,corners,corner_accuracy,(-1,-1),criteria)
imgpoints.append(corners2)
# Draw and display the corners
imgAugmnt = cv2.drawChessboardCorners(img, (n_row,n_col), corners2,ret)
cv2.imshow('Calibration',imgAugmnt)
cv2.waitKey(500)
# "c" pressed to compute calibration
elif k%256 == 99:
if n_img <= n_min_img:
print("Only ", n_img , " captured, ", " at least ", n_min_img , " images are needed")
else:
print("Computing calibration ...")
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, (width,height),None,None)
if not ret:
print("Cannot compute calibration!")
else:
print("Camera calibration successfully computed")
# Compute reprojection errors
for i in range(len(objpoints)):
imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
error = cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2)
tot_error += error
print("Camera matrix: ", mtx)
print("Distortion coeffs: ", dist)
print("Total error: ", tot_error)
print("Mean error: ", np.mean(error))
# Saving calibration matrix
try:
os.remove(result_file) #Delete old file first
except Exception as e:
#print(e)
pass
print("Saving camera matrix .. in ",result_file)
data={"camera_matrix": mtx.tolist(), "dist_coeff": dist.tolist()}
with open(result_file, "w") as f:
yaml.dump(data, f, default_flow_style=False)
# ESC pressed to quit
elif k%256 == 27:
print("Escape hit, closing...")
camera.release()
cv2.destroyAllWindows()
break
# "r" pressed to reset
elif k%256 ==114:
print("Reset program...")
Initialization = True
This the Camera Matrix:
818.6 0 324.4
0 819.1 237.9
0 0 1
Distortion coeffs:
0.34 -5.7 0 0 33.45
I was actually thinking that you should be able to solve your problem in a simple way:
mm_per_pixel = real_mm_width : 640px
Assuming that the camera initially moves in parallel to the plan with the object to pick [i.e. fixed distance], real_mm_width can be found measuring the physical distance corresponding to those 640 pixels of your picture. For the sake of an example say that you find that real_mm_width = 32cm = 320mm, so you get mm_per_pixel = 0.5mm/px. With a fixed distance this ratio doesn't change
It seems also the suggestion from the official documentation:
This consideration helps us to find only X,Y values. Now for X,Y
values, we can simply pass the points as (0,0), (1,0), (2,0), ...
which denotes the location of points. In this case, the results we get
will be in the scale of size of chess board square. But if we know the
square size, (say 30 mm), we can pass the values as (0,0), (30,0),
(60,0), ... . Thus, we get the results in mm
Then you just need to convert the centroid coordinates in pixels [e.g. (pixel_x_centroid, pixel_y_centroid) = (300px, 200px)] to mm using:
mm_x_centroid = pixel_x_centroid * mm_per_pixel
mm_y_centroid = pixel_y_centroid * mm_per_pixel
which would give you the final answer:
(mm_x_centroid, mm_y_centroid) = (150mm, 100mm)
Another way to see the same thing is this proportion where the first member is the measurable/known ratio:
real_mm_width : 640px = mm_x_centroid : pixel_x_centroid = mm_y_centroid = pixel_y_centroid

How can I display multiple windows concatenated with cv2 in array form?

I am capturing the frames in real time from various cameras. The output of each camera is displayed in a window with cv2.imshow. What I want to achieve now is that all the windows are concatenated forming a grid/matrix, for example, if I have 4 cameras, that the windows show me concatenated in 2x2.
Below I attach the code of what I have. Which allows me to capture the frames of the different cameras that I have, but I am not being able to do the above.
cap = []
ret = []
frame = []
final = ""
i = 0
cap.append(cv2.VideoCapture(0))
cap.append(cv2.VideoCapture(1))
cap.append(cv2.VideoCapture(2))
number_cameras = len(cap)
# I initialize values
for x in range(number_cameras):
ret.append(x)
frame.append(x)
while(True):
# I capture frame by frame from each camera
ret[i], frame[i] = cap[i].read()
if i == number_cameras-1:
final = cv2.hconcat([cv2.resize(frame[x], (400, 400)) for x in range(number_cameras)])
cv2.namedWindow('frame')
cv2.moveWindow('frame', 0, 0)
# I show the concatenated outputs
cv2.imshow('frame', final)
i = 0
else:
i = i + 1
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# I release the cameras
for x in range(number_cameras):
cap[x].release()
cv2.destroyAllWindows()
You can construct a frame out of 4 frames by resizing the frames to half their width and height. Then create an empty frame and fill it according to the resized width and height.
Since I don't currently have 4 cameras I simulating this using a single camera.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
ret, frame = cap.read()
#find half of the width
w = int(frame.shape[1] * 50 / 100)
#find half of the height
h = int(frame.shape[0] * 50 / 100)
dim = (w, h)
#resize the frame to half it size
frame =cv2.resize(frame, dim, interpolation = cv2.INTER_AREA)
#create an empty frame
output = np.zeros((h*2,w*2,3), np.uint8)
#place a frame at the top left
output[0:h, 0:w] = frame
#place a frame at the top right
output[0:h, w:w * 2] = frame
#place a frame at the bottom left
output[h:h * 2, w:w * 2] = frame
#place a frame at the bottom right
output[h:h * 2, 0:w] = frame
cv2.imshow("Output", output)
key = cv2.waitKey(1) & 0xFF
# if the `q` key was pressed, break from the loop
if key == ord("q"):
break
cv2.destroyAllWindows()

OpenCV CvCapture_MSMF::grabFrame videoio(MSMF): can't grab frame. Error: -2147483638

Below is my code for the invisibility cloak, I am getting this error
`anonymous-namespace'::SourceReaderCB::OnReadSample videoio(MSMF): OnReadSample() is called with error status: -1072875772 along with CvCapture_MSMF::grabFrame videoio(MSMF): can't grab frame. Error: -2147483638
can anyone please help me with this code.
import numpy as np
import cv2
import time #for camera setup time
videoCap = cv2.VideoCapture(0) #capture the video from 1st webcam
time.sleep(3) #2 sec for the camera to setup
background = 0 #background that I have to display when I have the cloth on myself
for i in range(60): #30 iteration to capture the background
ret, background = videoCap.read()
while(videoCap.isOpened()):
ret, img = videoCap.read()
if not ret:
break
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
lower_red = np.array([0, 120, 70])
upper_red = np.array([10, 255, 255])
mask1 = cv2.inRange(hsv, lower_red, upper_red) #seperating/segmenting the cloak part
lower_red = np.array([170, 120, 70])
upper_red = np.array([180, 255, 255])
mask2 = cv2.inRange(hsv, lower_red, upper_red)
mask1 = mask1 + mask2 # 1 or 2 i.e any shade of red between mask1 and mask2 then we need to segment that part
mask1 = cv2.morphologyEx(mask1, cv2.MORPH_OPEN, np.ones((3,3), np.uint8), iterations=2) #noise Removal
mask1 = cv2.morphologyEx(mask1, cv2.MORPH_DILATE, np.ones((3,3), np.uint8), iterations=1)
mask2 = cv2.bitwise_not(mask1) # mask2 == everything except the cloak
res1 = cv2.bitwise_and(background, background, mask=mask1) #Used for segmentation of the color
res2 = cv2.bitwise_and(img, img, mask=mask2) #used to substitute the cloak part
final_output = cv2.addWeighted(res1, 1, res2, 1, 0) #superimposing 2 images
cv2.imshow('We did it !!', final_output)
k = cv2.waitKey(10)
if k == 27:
break
videoCap.release()
cv2.destroyAllWindows()
The captured problem here is Microsoft Media Foundation API's MF_E_HW_MFT_FAILED_START_STREAMING:
A hardware device was unable to start streaming. This error code can be returned by a media source that represents a hardware device, such as a camera. For example, if the camera is already being used by another application, the method might return this error code.
This - in other words - means that the camera device is malfunctioning, the API is unable to start reading video frames. This low level error is then forwarded to you through OpenCV.

Using this motion detector code with a single webcam in a raspberry pi

No matter what I try I can't convert this code from Adrian Rosebrock to work with a single webcam, I have tested it as working with 2 webcams.
As far as I can tell the problem comes in attempting to convert this line;
for (stream, motion) in zip((webcam1, webcam2), (camMotion, piMotion)):
from __future__ import print_function
from pyimagesearch.basicmotiondetector import BasicMotionDetector
from imutils.video import VideoStream
import numpy as np
import datetime
import imutils
import time
import cv2
# initialize the video streams and allow them to warmup
print("[INFO] starting cameras...")
#webcam = VideoStream(src=0).start()
#picam = VideoStream(usePiCamera=True).start()
webcam1 = VideoStream(src=0).start()
webcam2 = VideoStream(src=1).start()
time.sleep(2.0)
# initialize the two motion detectors, along with the total
# number of frames read
camMotion = BasicMotionDetector()
piMotion = BasicMotionDetector()
total = 0
# loop over frames from the video streams
while True:
# initialize the list of frames that have been processed
frames = []
# loop over the frames and their respective motion detectors
for (stream, motion) in zip((webcam1, webcam2), (camMotion, piMotion)):
# read the next frame from the video stream and resize
# it to have a maximum width of 400 pixels
frame = stream.read()
frame = imutils.resize(frame, width=400)
# convert the frame to grayscale, blur it slightly, update
# the motion detector
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
locs = motion.update(gray)
# we should allow the motion detector to "run" for a bit
# and accumulate a set of frames to form a nice average
if total < 32:
frames.append(frame)
continue
# otherwise, check to see if motion was detected
if len(locs) > 0:
# initialize the minimum and maximum (x, y)-coordinates,
# respectively
(minX, minY) = (np.inf, np.inf)
(maxX, maxY) = (-np.inf, -np.inf)
# loop over the locations of motion and accumulate the
# minimum and maximum locations of the bounding boxes
for l in locs:
(x, y, w, h) = cv2.boundingRect(l)
(minX, maxX) = (min(minX, x), max(maxX, x + w))
(minY, maxY) = (min(minY, y), max(maxY, y + h))
# draw the bounding box
cv2.rectangle(frame, (minX, minY), (maxX, maxY),
(0, 0, 255), 3)
# update the frames list
frames.append(frame)
# increment the total number of frames read and grab the
# current timestamp
total += 1
timestamp = datetime.datetime.now()
ts = timestamp.strftime("%A %d %B %Y %I:%M:%S%p")
# loop over the frames a second time
for (frame, name) in zip(frames, ("Webcam", "Picamera")):
# draw the timestamp on the frame and display it
cv2.putText(frame, ts, (10, frame.shape[0] - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 255), 1)
cv2.imshow(name, frame)
# check to see if a key was pressed
key = cv2.waitKey(1) & 0xFF
# if the `q` key was pressed, break from the loop
if key == ord("q"):
break
# do a bit of cleanup
print("[INFO] cleaning up...")
cv2.destroyAllWindows()
webcam.stop()
picam.stop()
Thanks for the help

How do i save the image result from this code?

I'm trying to write a code that identifies the eyes of parakeets. So far, i have managed to use a code that identifies the circles edges and got great results at a certain threshold. But i can't save the result image.
I've tried using imwrite('result.png', clone) to save the result at the end of the code, but when I run it I'm get TypeError: Expected cv::UMat for argument 'img'.
I need the clone image to be colored too, but I've no idea where to start.
import cv2
import numpy as np
import imutils
def nothing(x):
pass
# Load an image
img = cv2.imread('sample.png')
# Resize The image
if img.shape[1] > 600:
img = imutils.resize(img, width=600)
# Create a window
cv2.namedWindow('Treshed')
# create trackbars for treshold change
cv2.createTrackbar('Treshold','Treshed',0,255,nothing)
while(1):
# Clone original image to not overlap drawings
clone = img.copy()
# Convert to gray
gray = cv2.cvtColor(clone, cv2.COLOR_BGR2GRAY)
# get current positions of four trackbars
r = cv2.getTrackbarPos('Treshold','Treshed')
# Thresholding the gray image
ret,gray_threshed = cv2.threshold(gray,r,255,cv2.THRESH_BINARY)
# Blur an image
bilateral_filtered_image = cv2.bilateralFilter(gray_threshed, 5, 175, 175)
# Detect edges
edge_detected_image = cv2.Canny(bilateral_filtered_image, 75, 200)
# Find contours
contours, _= cv2.findContours(edge_detected_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contour_list = []
for contour in contours:
# approximte for circles
approx = cv2.approxPolyDP(contour,0.01*cv2.arcLength(contour,True),True)
area = cv2.contourArea(contour)
if ((len(approx) > 8) & (area > 30) ):
contour_list.append(contour)
# Draw contours on the original image
cv2.drawContours(clone, contour_list, -1, (255,0,0), 2)
# there is an outer boundary and inner boundary for each eadge, so contours double
print('Number of found circles: {}'.format(int(len(contour_list)/2)))
#Displaying the results
cv2.imshow('Objects Detected', clone)
cv2.imshow("Treshed", gray_threshed)
# ESC to break
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
# close all open windows
cv2.destroyAllWindows()
I just tried this modification and it works flawlessly.
# ESC to break
k = cv2.waitKey(1) & 0xFF
if k == 27:
cv2.imwrite('result.png', clone)
break
There's either a misconception about when/where to call imwrite or something is messy with your python/opencv version. I ran it in pycharm using python 3.6.8 and opencv-python 4.0.0.21

Resources