So, I have this code, I can easily add a text or any shape in opencv frame.
But inserting an image on a frame is a very difficult one.
I want to insert a smaller image on a Videocapture frame, let say the image to be inserted is a 50x50 pixel.
Any idea on this?
import cv2
webcam = cv2.VideoCapture(0)
insertImage = "sample.jpg" # size 50x50
while True:
rval = False
while(not rval):
(rval, frame) = webcam.read()
if(not rval):
print("Failed to open webcam. Trying again...")
cv2.putText(frame, " image here ", (0,70),cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255,0,0), 2)
cv2.imshow('with image', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
webcam.release()
cv2.destroyAllWindows()
OpenCv images are numpy arrays. As far as I know, OpenCv does not provide functions with which you can get what you want. The result can be achieved by manipulating arrays.
import cv2
import numpy as np
if __name__ == '__main__':
bigImage = cv2.imread("image1.png") #I don't have a webcam connected, so it's your frame
smallImage = cv2.imread("image2.png") #50x50 for you
height, width, channels = smallImage.shape
offset = np.array((40, 50)) #top-left point from which to insert the smallest image. height first, from the top of the window
bigImage[offset[0]:offset[0] + height, offset[1]:offset[1] + width] = smallImage
cv2.imshow("test", bigImage)
cv2.waitKey(0)
Input
bigImage = big gray rectangle. It is your frame
smallImage = small green rectangle. It is your 50x50 image
Output
Related
As part of a project, I am trying to create a script that will
detect motion using a camera, and when doing so,
capture some frames of the feed for further analysis.
(But without delaying the actual feed!) Until now I am able to detect movement but without much say to the settings, so I am looking for a better solution.
What I cannot find a way to do is:
Hold on a frame while the feed plays.
What could help me a lot move forward:
a way to store X previous frames. (It will be empty for the first X frames, and afterwards it will be replaced with the a frame rolling frame set.)
or
a way to store a frame X seconds before the current. (It will be empty for the first X seconds, and afterwards it will be replaced with the new frame.)
What I have until now
import cv2, time, pandas # importing OpenCV, time and Pandas library
import threading
from datetime import datetime # importing datetime class from datetime library
My try to capture a previous frame, but it delays the feed:
def CheckFrame():
threading.Timer(100.0 , CheckFrame).start()
check, frame2 = video.read() # second image
return frame2
video = cv2.VideoCapture(0) # Capturing video
#check if connection with camera is successfully
if video.isOpened():
ret, frame = video.read() #capture a frame from live video
#check whether frame is successfully captured
if ret:
# continue to display window until 'q'/Esc is pressed Check end of code
while(True):
check, frame = video.read() #capture a frame from live video
# frame Converting color image to gray_scale image
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# frame Converting gray scale image to GaussianBlur so that change can be find easily
gray = cv2.GaussianBlur(gray, (21, 21), 10)
frame2 = CheckFrame()
# frame2 Converting color image to gray_scale image
gray2 = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
# frame2 Converting gray scale image to GaussianBlur so that change can be find easily
gray2 = cv2.GaussianBlur(gray2, (21, 21), 10)
# Difference between rame2f and current frame
diff_frame = cv2.absdiff(gray2, gray)
# If change in between static background and current frame is greater than 30 it will show white color(255)
thresh_frame = cv2.threshold(diff_frame, 2, 255, cv2.THRESH_BINARY)[1]
thresh_frame = cv2.dilate(thresh_frame, None, iterations = 1)
# Finding contour of moving object
cnts,_ = cv2.findContours(thresh_frame.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in cnts:
if cv2.contourArea(contour) < 1000:
continue
(x, y, w, h) = cv2.boundingRect(contour)
# making green rectangle around the moving object
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 3)
cv2.imshow("Color Frame", frame) # Displaying color frame with contour of motion of object
#cv2.imshow("Gray Frame", gray) # Displaying image in gray_scale
cv2.imshow("Threshold Frame", thresh_frame) # Displaying the black and white image in which if intensity difference greater than 30 it will appear white
cv2.imshow("Difference Frame", diff_frame) # Displaying the difference in currentframe to the staticframe(very first_frame)
if cv2.waitKey(1) & 0xFF == 27: #press 'Esc' to break out of the loop
#if cv2.waitKey(1) & 0xFF == ord('q'): #press 'q' to break out of the loop
break
#print error if frame capturing was unsuccessful
else:
print("Error : Failed to capture frame")
video.release()
# Destroying all the windows
cv2.destroyAllWindows()
# print error if the connection with camera is unsuccessful
else:
print("Cannot open camera")
Ive got a video which ive im trying to show a specific region using cv2.polyfill and bitwise operation. When I do this on a image it works fine but when done on a video it comes up with the following error. Ive had no problems doing this earlier on with another picture/video. The region to be shown does show up as a frozen picture but also crashes the kernel. The code is:
import cv2
import numpy as np
cap = cv2.VideoCapture("heartvideo.wmv",0)
def roi(frame):
mask = np.zeros_like (frame)
array = np.array([[148,550],[300,650],[400,680],[800,680],[880,560],[555,70],[492,50]])
contours = np.array([[50,50], [50,150], [150,150], [150,50]])
cv2.fillPoly(mask, pts = [array], color =(255))
masked = cv2.bitwise_and(mask,frame)
return mask
while(cap.isOpened()): # while video is initialised
ret, frame = cap.read() #reads the video bit by bit
adj = roi(frame)
if ret:
cv2.imshow("Image", adj)
else:
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
if cv2.waitKey(15) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
error: OpenCV(4.5.3) :-1: error: (-5:Bad argument) in function 'fillPoly'
Overload resolution failed:
img data type = 17 is not supported
Expected Ptr<cv::UMat> for argument 'img'
The issue is that you're using a 3-channel BGR mask (datatype 17 is a 3-channel image). You used np.zeros_like(frame) to set your mask which means that it'll have the exact same dimensions as the image you passed in. If you meant for it to be a 1-channel image you should set the dimensions.
I'm not sure what version of OpenCV you're using and I can't replicate the error with OpenCV 4.4. On this version it allows a 3-channel image even if you've specified a 1-channel color as the fillPoly argument though it does this by assuming you meant (255,0,0) for the color. It could be that on a different version of OpenCV the color dimensions had to match the image dimensions and it's complaining about that.
Try out this revised version of the code and see if it works.
import cv2
import numpy as np
def roi(frame):
# draw a polygon on mask
height,width = frame.shape[:2];
mask = np.zeros((height, width), np.uint8);
array = np.array([[148,550],[300,650],[400,680],[800,680],[880,560],[555,70],[492,50]])
contours = np.array([[50,50], [50,150], [150,150], [150,50]])
cv2.fillPoly(mask, pts = [array], color =(255))
# mask stuff on frame
# masked = cv2.bitwise_and(mask,frame)
copy = np.zeros_like(frame);
copy[mask == 255] = frame[mask == 255];
return copy;
# open video
cap = cv2.VideoCapture("heartvideo.wmv", 0);
while(cap.isOpened()): # while video is initialised
ret, frame = cap.read() #reads the video bit by bit
if ret:
adj = roi(frame)
cv2.imshow("Image", adj)
else:
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
if cv2.waitKey(15) == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Replace sub part of matrix by another small matrix in numpy generally seems to work for my purposes but I'm running into something I can't reconcile. Consider the following code, that creates two 3D matrices the shape of OpenCV2 webcam input, (in my case (480, 640, 3)), one of all 1s (frame) and one of random floats (rgb_noise_mask), replaces a specified submatrix in frame with the same submatrix of rgb_noise_mask, and displays it to the screen. This code works as intended, displaying a block of RGB-based static on a field of white.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
frame = np.ones(frame.shape)
rgb_noise_mask = np.random.random(size=frame.shape)
while True:
boxes = [[300,300,30,30]]
for box in boxes:
x, y, width, height = box
frame[y:y2, x:x2] = rgb_noise_mask[y:y2, x:x2]
cv2.imshow("frame", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cap.release()
cv2.destroyAllWindows()
Now take off the training wheels and use the actual webcam input instead of faking it. That same box now appears as uniform black instead of the expected colors:
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
rgb_noise_mask = np.random.random(size=frame.shape)
while True:
ret, frame = cap.read()
boxes = [[300,300,30,30]]
for box in boxes:
x, y, width, height = box
frame[y:y2, x:x2] = rgb_noise_mask[y:y2, x:x2]
cv2.imshow("frame", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cap.release()
cv2.destroyAllWindows()
Why is this, and how can I get around it? Further adding to my confusion is that if I replace frame[y:y2, x:x2] = rgb_noise_mask[y:y2, x:x2] with frame[y:y2, x:x2] = frame[y:y2, x:x2][::-1] in the second code sample it behaves as expected and displays the live output with that square mirrored.
The issue here is that ret, frame = cap.read() returns frame as a numpy array with dtype=np.uint8, while rgb_noise_mask is float between 0,1, so all 0 when converted to uint8.
A simple fix is to generate noise as integers with randint:
rgb_noise_mask = np.random.randint(0,256, size=frame.shape, dtype=np.uint8)
This question already has answers here:
OpenCV Error: (-215)size.width>0 && size.height>0 in function imshow
(17 answers)
Closed 2 years ago.
I've seen the other stack exchange posts about this exact same error, but instead of reading from an image or a list of images, my script reads from a webcam. BTW, this script is copied, and i'm trying to get it working as an example for me to learn how it all works.
import numpy as np
import cv2
# set up HOG person detector and create hog object
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
cv2.startWindowThread()
# set up video capture, make cap video stream object
cap = cv2.VideoCapture(0)
# write file output to output.avi in 640x480 size
out = cv2.VideoWriter(
'output.avi',
cv2.VideoWriter_fourcc(*'MJPG'),
15.,
(640,480))
if cap is not None:
while(True):
# read the webcam
ret, frame = cap.read()
# resizing for faster detection
frame = cv2.resize(frame, (640, 480))
# using a greyscale picture, also for faster detection
gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
# detect people in the image
# returns the bounding boxes for the detected objects
boxes, weights = hog.detectMultiScale(frame, winStride=(8,8) )
boxes = np.array([[x, y, x + w, y + h] for (x, y, w, h) in boxes])
for (xA, yA, xB, yB) in boxes:
# display the detected boxes in the colour picture
cv2.rectangle(frame, (xA, yA), (xB, yB),
(0, 255, 0), 2)
# Write the output video
out.write(frame.astype('uint8'))
# Display the resulting frame
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
# and release the output
out.release()
# finally, close the window
cv2.destroyAllWindows()
cv2.waitKey(1)
I understand that the error is caused because there is no image for the resize function to resize, so I added the if cap is not None: statement, but I still get the same error. How can I fix this in this script?
From what I've gathered from your post above, you don't want to use a webcame in any sort of capacity. If so, You might be experiencing some errors with this portion of the script
# set up video capture, make cap video stream object
cap = cv2.VideoCapture(0)
# write file output to output.avi in 640x480 size
out = cv2.VideoWriter(
'output.avi',
cv2.VideoWriter_fourcc(*'MJPG'),
15.,
(640,480))
Here you are setting up a video stream, then loading in an avi. If you just want to read in an image you can use the below code.
import numpy as np
import cv2
# Load an color image in grayscale
img = cv2.imread('inputImage.jpg',0)
#Display the input image
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
You can find more about images and Opencv below.
https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_gui/py_image_display/py_image_display.html
I want to count the cars by using haar cascade.
#import libraries of python opencv
import numpy as np
import cv2
import gc
import uuid
import datetime
import time
import csv
cap = cv2.VideoCapture('v3.mp4')
car_cascade = cv2.CascadeClassifier('cars.xml')
W = cap.get(3)
H = cap.get(4)
areaTH = 700
H1 = (H/2)+10
W1 = W/2
mx = 0
my = 30
while (cap.isOpened()):
#capture frame by frame
ret, frame = cap.read()
#convert video into gray scale of each frames
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#detect cars in the video
cars = car_cascade.detectMultiScale(gray, 1.1, 3)
#to draw arectangle in each cars
for (x,y,w,h) in cars:
cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)
#display the resulting frame
cv2.imshow('video', frame)
#press Q on keyboard to exit
if cv2.waitKey(25) & 0xFF == ord('q'):
break
Line1 = np.array([[20,H1],[310,H1]], np.int32).reshape((-1,1,2))
frame = cv2.polylines(frame,[Line1],False,(0,0,255),thickness=5)
fram, contours0, hierarchy =
cv2.findContours(frame,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
for cnt in contours0:
# cv2.drawContours(frame, cnt, -1, (0,255,0), 2, 8)
area = cv2.contourArea(cnt)
#print ('Area : '+str(area))
if area > areaTH:
#################
# TRACKING #
#################
M = cv2.moments(cnt)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
x,y,w,h = cv2.boundingRect(cnt)
cv2.circle(frame,(cx,cy), 3, (255,0,0), -1)
img = cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)
#print ('H1 : '+str(H1))
print('cy : '+str(cy))
if (cy >= 147) and (cy<= 155):
Vehicles = Vehicles + 1
Line1 = np.array([[200,H1],[880,H1]],
np.int32).reshape((-1,1,2))
frame = cv2.polylines(frame,[Line1],False,(255,0,0),thickness=5)
cv2.imshow('Frame',frame)
#Abort and exit with 'Q' or ESC
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release() #release video file
cv2.destroyAllWindows()
I convert the image properly to gray-scale and successfully drawn a line on the frame the problem is that I am getting this error
error: OpenCV(3.4.2) C:\build\3_4_winpack-bindings-win32-vc14-static\opencv\modules\imgproc\src\contours.cpp:199: error: (-210:Unsupported format or combination of formats) [Start]FindContours supports only CV_8UC1 images when mode != CV_RETR_FLOODFILL otherwise supports CV_32SC1 images only in function 'cvStartFindContours_Impl'
when ever i pass a variable 'frame' in this code line can somebody help me to solve this error thanx
fram, contours0, hierarchy =
cv2.findContours(frame,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
If you look at OpenCV documentation you see that function cv2.findContour() requires monochrome images. You pass frame which is still in 3 channels. You should use the gray variable instead (cv2.findContours(gray,...).
From the documentation for cv2.findContour()
image – Source, an 8-bit single-channel image. Non-zero pixels are treated as 1’s. Zero pixels remain 0’s, so the image is treated as binary . You can use compare() , inRange() , threshold() , adaptiveThreshold() , Canny() , and others to create a binary image out of a grayscale or color one. The function modifies the image while extracting the contours. If mode equals to CV_RETR_CCOMP or CV_RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1).
Try this line to scale the pixels
image = cv2.convertScaleAbs(image)