image of the program execution
I'm trying to make a program that shows a video streaming of an usb camera and a tkinter app. I use opencv for displaying the image but i'm not plotting the image in the tkinter app.
The program is for controlling a differential robot using the information about the position and orientation obtained from the camera. The first step is to connect the pc to the raspberry (the raspberry sends via serial port commands to the robot) and when I click the button "Conectar" the camera stream stops. But if I use the laptop camera, the camera stream doesn't stop. I don't undserstand why. But I need to not stop the streaming because it also happens with the button "Ir al punto", which execute the function that lead the robot to the destination point. And if the streaming is stopped, the information about the position and orientation is not correct and the robot can't reach the point.
I use threading to display the camera:
# Creation of the tkinter app: labels, buttons....
# I'm not showing this because is too long
# Camera parameters
cv2.namedWindow("Zoom")
cv2.moveWindow("Zoom", 0,512)
cv2.moveWindow("Visualization", 0,0)
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FPS, 30)
detector = apriltag.Detector()
zoomed = np.zeros((300, 300, 3), dtype=np.uint8)
# Threading
t1 = threading.Thread(target=show_camera2) # show_camera2() is the typical opencv videocapture imshow loop
t1.start()
root.mainloop()
I've tried to merge the opencv windows in the tkinter app using this:
imgframe = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
img1 = Image.fromarray(imgframe)
imgtk1 = ImageTk.PhotoImage(image=img1)
label_camera.imgtk = imgtk1
label_camera.configure(image=imgtk1)
label_camera.update()
but still stopping when pressing a button.
all. I have a very strange issue, reading the VideoCapture in OpenCV.
I have .MTS videos (MPEG2), and I read them in OpenCV using the next code:
cv2.namedWindow("frame", cv2.WINDOW_NORMAL)
cap = cv2.VideoCapture("00030.MTS")
while(cap.isOpened()):
ret,frame = cap.read()
cv2.imshow("frame", frame)
cv2.waitKey(0)
And this shows me the corrupted frames (with bands on them). The same quality is kept, if I save the frame as the image, and look at It outside the OpenCV.
But how It should look like:
I've never seen this before while working with .avi or .mp4
How can I get the same not-corrupted frames like in the media player?
(I edited the title of the question. Some of this information wasn't apparent originally.)
Your file names suggest that this video material is a video camera's own recording, with no alterations to it.
Your video seems to be "interlaced", i.e. not "progressive". Interlaced video consists of "fields" instead of complete frames. A field contains all the even or odd lines of an image. Even and odd fields follow each other. With that method, you can have "50i" video that updates at 50 Hz, yet requires only half the data of a full "50p" video (half the data means reduced vertical resolution).
OpenCV (probably) uses ffmpeg to read your video file.
Both ffmpeg and VLC know when a video file contains interlaced video data. VLC automatically applies a suitable filter to make this data nicer to look at. ffmpeg does not, because filtering costs processing time and changes the data.
You should use ffmpeg to "de-interlace" your video files. I would suggest the yadif filter.
Example:
ffmpeg -i 00001.MTS -c copy -vf yadif -c:v libx264 -b:v 24M 00001_deinterlaced.MTS
You should look at the settings/options of yadif. Maybe the defaults aren't to your liking. Try yadif=1 to get field-rate progressive video (50/60p).
I am trying to do face detection in Open CV , however when i run my code i see camera light in laptop on , but the frame does not show up on system .
Can anyone help ?
below is the code
print("[INFO] loading model .....")
net = cv2.dnn.readNetFromCaffe(args["prototxt"],args["model"])
initialize video stream
print("[INFO] starting video stream ....")
vs =VideoStream(src=0).start()
time.sleep(1.0)
while True:
frame = vs.read()
frame =imutils.resize(frame,width=400)
(h,w)=frame.shape[:2]
blob = cv2.dnn.blobFromImage(cv2.resize(frame,(300,300)),1.0,(300,300),(104.0,177.0,123.0))
Try changing src=1 instead of src=0
vs =VideoStream(src=1).start() time.sleep(1.0)
I am trying to make something like a video player using Python. Quick google search showed me how to play a video using OpenCV. But video rendered using OpenCV is not as crisp as the video played by VLC media player. The images of both players are shown below.
OpenCV rendering
Video in VLC media player
I have checked the width and height of the images rendered by OpenCV and it is 1080p. But somehow the video is not as crisp as it should be. Here is the code used to render the images.
def start_slideshow_demo(video_file_path: str):
cap = cv2.VideoCapture(video_file_path)
cv2.namedWindow(video_file_path, cv2.WINDOW_GUI_EXPANDED)
cv2.setWindowProperty(video_file_path, cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
while(cap.isOpened()):
ret, frame = cap.read()
if ret == True:
cv2.imshow(video_file_path, frame)
if cv2.waitKey(25) & 0xFF == ord('q'):
break
else:
break
cap.release()
cv2.destroyAllWindows()
Any help is appreciated. Thank you.
i don think it's Opencv issue. I used your code as it is in my desktop.
(left : opencv - right VLC player)
I'm trying to process live screen. There is a game about catching fish. You have to click on fish when it is in circle. I think that I can process my screen with opencv, find fish and click on it with pyautogui.
I did it but problem is program not fast enough to click. By the way game is a mini game in Metin 2 mmorpg. It is like a hack or bot but I just wondering if can I do that.
Here is my code:
import numpy as np
import cv2
from PIL import ImageGrab
import pyautogui
import time
while True:
img=ImageGrab.grab(bbox=(341,208,430,290))
img_np=np.array(img)
#gray=cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY)
#lower=np.array([57,91,120])
#upper=np.array([65,95,160])
#mask=cv2.inRange(gray,95,130)
#sonuc=cv2.bitwise_and(gray,gray,mask=mask)
#cv2.imshow('frame',mask)
degsk=np.argwhere(img_np==[123,90,57])
if len(degsk)!=0:
#print(degsk)
yerx=341+degsk[int(len(degsk)/2),1]
yery=208+degsk[int(len(degsk)/2),0]
#pyautogui.click(x=yerx, y=yery)
time.sleep(0.8)
if cv2.waitKey(1)&0xFF==ord('q'):
break
cv2.destroyAllWindows()
As you can see, first I tried mask the screen than I realise that it is not necessary so I found BGR value of fish and programed to find it in numpy array than I took value middle in the array and than i used mouse move function. As I said this is not fast enough to catch fish.
So the program is working but delayed for catch fish. How can I make faster this program?
Game Screen Here
Using mss is really fast. Try this:
import time
import cv2
import mss
import numpy
with mss.mss() as sct:
# Part of the screen to capture
monitor = {"top": 40, "left": 0, "width": 800, "height": 640}
while "Screen capturing":
last_time = time.time()
# Get raw pixels from the screen, save it to a Numpy array
img = numpy.array(sct.grab(monitor))
# Display the picture
cv2.imshow("OpenCV/Numpy normal", img)
# Display the picture in grayscale
# cv2.imshow('OpenCV/Numpy grayscale',
# cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY))
print("fps: {}".format(1 / (time.time() - last_time)))
# Press "q" to quit
if cv2.waitKey(25) & 0xFF == ord("q"):
cv2.destroyAllWindows()
break
More information on https://python-mss.readthedocs.io/index.html
I find IPython best for timing things, so if you start IPython and paste in the following code:
from PIL import ImageGrab
img=ImageGrab.grab(bbox=(341,208,430,290))
You can then time a statement with:
%timeit img=ImageGrab.grab(bbox=(341,208,430,290))
and I get this:
552 ms ± 5.91 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
So, grabbing the screen takes over 500ms, so you are only going to get under 2 frames/second - without even processing it.
If you want to grab the screen faster, I would suggest ffmpeg. I installed it on my iMac running macOS with homebrew using:
brew install ffmpeg
I can then see the list of available video sources and find what I need to record the screen with:
ffmpeg -f avfoundation -list_devices true -i ""
Sample Output
[AVFoundation input device # 0x7fa7dcf05b40] AVFoundation video devices:
[AVFoundation input device # 0x7fa7dcf05b40] [0] FaceTime HD Camera
[AVFoundation input device # 0x7fa7dcf05b40] [1] Capture screen 0 <--- THIS ONE IS THE SCREEN
[AVFoundation input device # 0x7fa7dcf05b40] AVFoundation audio devices:
[AVFoundation input device # 0x7fa7dcf05b40] [0] MacBook Pro Microphone
[AVFoundation input device # 0x7fa7dcf05b40] [1] CalDigit Thunderbolt 3 Audio
So I know I need input 1 for the screen.
So, if I want to record the screen from top-left corner (0,0) at a width of 400px and height of 200px at 20fps for 10s and pass RGBA8888 data to my fishing program, I can do this:
ffmpeg -y -pix_fmt bgr0 -f avfoundation -r 20 -t 10 -i 1 -filter:v "crop=400:200:0:0" -f rawvideo - | ./fish.py
I can now use the following as my fishing program:
#!/usr/bin/env python3
import numpy as np
import pyautogui
import time
import os, sys
# width, height
w, h = 400, 200
# Bytes per frame - assumes bgr0, i.e. 8-bits of blue, 8-bits red. 8-bits green and 8-bits junk
bytesPerFrame = w * h * 4
while True:
img = sys.stdin.buffer.read(bytesPerFrame)
if len(img) != bytesPerFrame:
break
# Process your video here
Keywords: pyautogui, screen grab, screen-grab, screengrab, slow, Mac, macOS, Python, capture, screen capture, ffmpeg, PIL, OpenCV