Closing an image window displays another window. Why? - python

I'm stuck. My code sucks. My silders don't work either, but the infinite image windows are driving me nuts. When I close the namedWindow, it opens a new display window with the image (infinitely). Help?
import numpy as np
import cv2
from pylepton import Lepton
#setup the Lepton image buffer
def capture(device = "/dev/spidev0.0"):
with Lepton() as l:
a,_ = l.capture() #grab the buffer
cv2.normalize(a, a, 0, 65535, cv2.NORM_MINMAX) # extend contrast
np.right_shift(a, 8, a) # fit data into 8 bits
return np.uint8(a)
#Create a window and give it features
def nothing(x):
pass
cv2.namedWindow('flir', cv2.WINDOW_NORMAL)
cv2.moveWindow('flir',1,1)
cv2.createTrackbar('thresh','flir',50,100,nothing)
cv2.createTrackbar('erode','flir',5,100,nothing)
cv2.createTrackbar('dilate','flir',7,100,nothing)
#process the buffer into an image on a continuous loop
while True:
#update the image processing variables
thresh = cv2.getTrackbarPos('thresh', 'flir')
erodeSize = cv2.getTrackbarPos('erode', 'flir')
dilateSize = cv2.getTrackbarPos('dilate', 'flir')
image = capture()
#apply some image processing
blurredBrightness = cv2.bilateralFilter(image,9,150,150)
thresh = 50
edges = cv2.Canny(blurredBrightness,thresh,thresh*2, L2gradient=True)
_,mask = cv2.threshold(blurredBrightness,200,1,cv2.THRESH_BINARY)
erodeSize = 5
dilateSize = 14
eroded = cv2.erode(mask, np.ones((erodeSize, erodeSize)))
mask = cv2.dilate(eroded, np.ones((dilateSize, dilateSize)))
adjusted_image = cv2.resize(cv2.cvtColor(mask*edges, cv2.COLOR_GRAY2RGB) | image, (640, 4$
final_image = cv2.applyColorMap(adjusted_image, cv2.COLORMAP_HOT)
#display the image
cv2.imshow('flir', final_image)
if cv2.waitKey(1) == ord('q'):
break
cv2.waitKey()
cv2.destroyWindow('flir')

Firstly, Calm down.
Secondly, look at your code closely. Closing the window wouldn't do you any good, because of the lines:
cv2.imshow('flir', final_image)
and
cv2.destroyWindow('flir')
What these 2 are doing in tandem is that you're displaying a frame in a new window, and then destroying it, then recreating that window in imshow, then displaying the next frame and destroying it...and so on and so forth.
That should explain your flickering windows.
To stop execution of your program, you've added this code:
if cv2.waitKey(1) == ord('q'):
break
What this implies is that when you press 'q' on your keyboard while your image window is in focus, your while loop will break and your program will terminate.
So I would advise you to remove cv2.destroyWindow and use 'q' key to quit your application than to close it using your mouse.

Related

how to resize live video in python cv2 using .set()?

I am learning opencv with https://www.youtube.com/watch?v=oXlwWbU8l2o&ab_channel=freeCodeCamp.org this tutorial and I arrived at part 3 (resizing and rescaling). Towards the end he creates this function which should be better for live video. The function doesn't return anything and he doesn't show how it works. The funtion is change_res(width, height) and I think it should be called in the while loop for frame_resized.
import cv2 as cv
def rescale_frame(frame, scale): # works for image, video, live video
width = int(frame.shape[1] * scale)
height = int(frame.shape[0] * scale)
dimensions = (width, height)
return cv.resize(frame, dimensions, interpolation=cv.INTER_AREA)
def change_res(width, height): # works only for live video
capture.set(3, width)
capture.set(4, height)
capture = cv.VideoCapture(0) # integer to capture from webcam, path to capture video file
while True:
isTrue, frame = capture.read()
frame_resized = rescale_frame(frame, scale=.2) # this line
cv.imshow("Video", frame)
cv.imshow("Video Resized", frame_resized)
if cv.waitKey(20) & 0xFF == ord("q"): # press "q" key to exit loop
break
capture.release()
cv.destroyAllWindows()
Thanks to #Dan MaĊĦek 's comment I managed to understand.
The .set() method changes the resolution of the camera, it doesnt need to be in the while loop because capture = cv.VideoCapture(0) keeps going by defeault forever unless capture.release() is called.
import cv2 as cv
def rescale_frame(frame, scale): # works for image, video, live video
width = int(frame.shape[1] * scale)
height = int(frame.shape[0] * scale)
dimensions = (width, height)
return cv.resize(frame, dimensions, interpolation=cv.INTER_AREA)
capture = cv.VideoCapture(0) # integer to capture from webcam, path to capture video file
capture.set(3, 1440)
while True:
isTrue, frame = capture.read()
frame_resized = rescale_frame(frame, scale=.2)
cv.imshow("video with set", frame)
cv.imshow("Video Resized", frame_resized)
if cv.waitKey(20) & 0xFF == ord("q"): # press "q" key to exit loop
break
capture.release() # stop capturing the image/video
cv.destroyAllWindows() # close windows
So, I wanted a small and a big window showing what the webcam was capturing. Currently this code captures the video, makes it 2560x1440 (with .set) which is enormous and then it takes those frames and rescales them with the rescale_frame function to make it smaller.
I found out that this .set() method is more efficient for a single video but if I want two I should show as small the default one and then use rescale_frame to make it bigger.

My Screen Recorder built using OpenCV and PyAutoGUI records only one frame

I am building a Screen Recorder in Python using numpy, OpenCV and PyAutoGUI. I have used tkinter for GUI Purposes. The problem with my screen recorder is that it records only one frame when I click on the Record Screen Button and then the screen gets jammed and I can't do anything. Here is my code so far:
from tkinter import *
import cv2
import numpy as np
import pyautogui
resolution = (1366,768)
Specify video codec:
codec = cv2.VideoWriter_fourcc(*"XVID")
Specify name of Output file:
filename = "Recordings.avi"
Specify frames rate (we can choose any value and experiment with it):
fps = 30.0
Creating a VideoWriter object:
out = cv2.VideoWriter(filename, codec, fps, resolution)
def startRecording():
window.iconify()
while True:
img = pyautogui.screenshot()
# Convert the screenshot to a numpy array
frame = np.array(img)
# Convert it from BGR(Blue, Green, Red) to
# RGB(Red, Green, Blue)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Write it to the output file
out.write(frame)
def stopRecording():
cv2.destroyAllWindows()
out.release()
window.destroy()
window = Tk()
window.title("Screen Recorder")
window.geometry("400x150")
window.config(bg='pink')
recordButton = Button(window,text="Record(F9)",font=("Bell MT",20),width=20,command=startRecording)
recordButton.pack(pady=(10,0))
stopButton = Button(window,text="Stop(F10)",font=("Bell MT",20),width=20,command=stopRecording)
stopButton.pack(pady=(10,0))
mainloop()
You cannot do a blocking call in a button callback.
As you wrote it startRecording will never end and will hence block tkinter mainloop. The recording probably works but your UI becomes unresponsive.
Your best shot would be to schedule the recording (look for the after method): record one frame every x millisecond.
Here is a simplified example based on your original code (you need to complete it)
continueRecording = True # must be declared before stopRecording
window = Tk() # must be declared before recordOneFrame
def stopRecording():
global continueRecording
continueRecording = False
def recordOneFrame():
global continueRecording
img = pyautogui.screenshot()
# Convert the screenshot to a numpy array
frame = np.array(img)
# Convert it from BGR(Blue, Green, Red) to
# RGB(Red, Green, Blue)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Write it to the output file
out.write(frame)
if continueRecording:
window.after(round(1/25. * 1000),recordOneFrame)
def startRecording():
recordOneFrame()

Sending ROS messages through a cv2 python script

I am trying to implement a robotic solution, where the user will click on a point through a camera feed of an area and the mobile 4 wheel robot will path its way to that location.
I have created the part of translating video pixel coordinates to ground coordinates through the use of the homograph transformation and would like to implement the part of sending the ground coordinates to RViz.
The part of calculating the ground coordinates is shown bellow:
global h
font = cv2.FONT_HERSHEY_SIMPLEX #Loading neccessary fonts
with open("save.h", "rb") as f:
h = load(f)
print "Homographic matrix loaded successfully."
def draw_circle2(event,x,y,flags,param):
global h,mouseX,mouseY, num_of_points, complete,np_coord_on_screen,np_coord_on_ground, myImage, emptyFrame, coord_on_screen, coord_on_ground
if event == cv2.EVENT_LBUTTONDBLCLK:
a = np.array([[x, y]], dtype='float32')
a = np.array([a])
pointOut = cv2.perspectiveTransform(a, h) #Calculation of new point location
loc_pointOut = tuple(pointOut)
pointOut=(loc_pointOut[0][0][0],loc_pointOut[0][0][1]) #Point on ground
print "Current Location: "+str(pointOut)
cv2.imshow('Video',emptyFrame) #Showing emptyFrame
cv2.circle(myImage,(x,y),4,(255,0,0),-1) #Draw a circle on myImage
cv2.putText(myImage,(str((round(pointOut[0],2)))+","+str(round(pointOut[1],2))), (x-5,y-15),font, 0.4,(0,255,0)) #Draw the text
cv2.imshow('Video',myImage) #Showing resulting myImage
myImage = emptyFrame.copy()
# Initial code
# Showing first frame on screen
raw_input("Press any key...")
clear_all()
cv2.namedWindow('Video') #Naming the window to use.
cv2.setMouseCallback('Video',draw_circle2) #Set mouse callBack function.
ret, frame = cap.read() #Get image from camera
if (ret): #If frame has image, show the image on screen
global myImage, emptyFrame
myImage = frame.copy()
emptyFrame = frame.copy()
cv2.imshow('Video',myImage) # Show the image on screen
while True: # making a loop
if cv2.waitKey(1) & 0xFF == ord('q'):
break
if (cv2.waitKey(1) & 0xFF == ord('c')):
#Deleting points from image
cv2.imshow('Video',emptyFrame) #Show the image again, deleting all graphical overlays like text and shapes
coord_on_screen = [] #Resetting coordinate lists
coord_on_ground=[] #Resetting coordinate lists
if (cv2.waitKey(1) & 0xFF == ord('s')):
cap.release()
cv2.destroyAllWindows()
init()
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
So, pointOut is the point on the ground (example: (2,4) m)
I need some directions on how to implement the creation of a node and the transmission of the pointOut Marker message to a ROS topic in my code.
My configuration is ROS Kinetic Kame, Python 2.7

Previewing line when drawing with opencv

I want to make a simple draw function to draw a line, but I want it to be previewed while it's being drawn; on EVENT_MOUSEMOVE it should draw the line continuously, while not saving it (e.g. how MS paint behaves when you draw a line and can see the output, which is saved when you release the mouse button).
I've used the "more advanced demo" here, where I use the input image as a global, make a copy of it, and then overwrite the image with the copy after drawing, but it doesn't actually make any difference (I neither see the "preview" of the line, and all the lines I draw stay on the canvas) and I can't see why:
img = None
def draw_circle(event,x,y,flags,param):
global ix,iy,drawing,mode,img
img_c = img.copy()
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix,iy = x,y
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
if mode == True:
cv2.line(img,(ix,iy),(x,y),(0,255,0),1)
img = img_c.copy()
else:
cv2.circle(img,(x,y),5,(0,0,255),-1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
if mode == True:
cv2.line(img,(ix,iy),(x,y),(0,255,0),1)
else:
cv2.circle(img,(x,y),5,(0,0,255),-1)
while(1):
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
To preview a line while drawing it, you need to update the image every time you move the mouse, but you need to keep the original to only draw one line. If the line changes orientation the idea is not to draw multiple lines, but to show only one line.
Here is a sample code of what I am talking about. I start with a black canvas, then I preview the line in blue, and once it is finish it becomes green. Read the comments inside the code to understand the details. If you have any questions just comment :)
import numpy as np
import cv2
# create black canvas of size 600x600
img = np.zeros((600, 600, 3), dtype=np.uint8)
# intialize values in unusable states
preview = None
initialPoint = (-1, -1)
# mouse callback
def drawLine(event,x,y,flags,param):
global initialPoint,img, preview
if event == cv2.EVENT_LBUTTONDOWN:
# new initial point and preview is now a copy of the original image
initialPoint = (x,y)
preview = img.copy()
# this will be a point at this point in time
cv2.line(preview, initialPoint, (x,y), (0,255,0), 1)
elif event == cv2.EVENT_MOUSEMOVE:
if preview is not None:
# copy the original image again a redraw the new line
preview = img.copy()
cv2.line(preview, initialPoint, (x,y), (0,255,0), 1)
elif event == cv2.EVENT_LBUTTONUP:
# if we are drawing, preview is not None and since we finish, draw the final line in the image
if preview is not None:
preview = None
cv2.line(img, initialPoint, (x,y), (255,0,0), 1)
# set the named window and callback
cv2.namedWindow("image")
cv2.setMouseCallback("image", drawLine)
while (True):
# if we are drawing show preview, otherwise the image
if preview is None:
cv2.imshow('image',img)
else :
cv2.imshow('image',preview)
k = cv2.waitKey(1) & 0xFF
if k == ord('q'):
break;
cv2.destroyAllWindows()

opencv window not closing after calling destroyAllWindows() function

I am implementing camshift algorithm in python using opencv and using the position given by it to move my mouse and draw on the kolour application.
When i press the button on in tkinter ui a frame launches and then
Upon pressing the key 'q' the 'frame' does not close, The frame just freezes and the option to force quit comes. I am using tkinter for UI.
global paint_open
paint_open = 0
def func():
global frame, roiPts, inputMode ,token
camera = cv2.VideoCapture(0)
cv2.namedWindow("frame")
cv2.setMouseCallback("frame", selectROI)
termination = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
roiBox = None
li=[]
while True:
(grabbed, frame) = camera.read()
if roiBox is not None:
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
backProj = cv2.calcBackProject([hsv], [0], roiHist, [0, 180], 1)
(r, roiBox) = cv2.CamShift(backProj, roiBox, termination)
pts = np.int0(cv2.cv.BoxPoints(r))
li.append(pts)
#coordinates contain the coordinates of the tracked object
coordinates = r[0]
# x, y contains the coordinates
x = int(coordinates[0])
y = int(coordinates[1])
drawing(x,y)
#draws a circle around the center from x,y
cv2.circle(frame, (int(x), int(y)), 4, (0, 0, 255), 2)
#draws a colored frame around the object
cv2.polylines(frame, [pts], True, (255, 0, 0), 2)
#here imshow function start
cv2.imshow("frame", frame)
key = cv2.waitKey(1) & 0xFF
# handle if the 'i' key is pressed, then go into ROI
if key == ord("i") and len(roiPts) < 4:
inputMode = True
orig = frame.copy()
while len(roiPts) < 4:
cv2.imshow("frame", frame)
cv2.waitKey(0)
roiPts = np.array(roiPts)
s = roiPts.sum(axis = 1)
tl = roiPts[np.argmin(s)]
br = roiPts[np.argmax(s)]
roi = orig[tl[1]:br[1], tl[0]:br[0]]
roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
roiHist = cv2.calcHist([roi], [0], None, [16], [0, 180])
roiHist = cv2.normalize(roiHist, roiHist, 0, 255, cv2.NORM_MINMAX)
roiBox = (tl[0], tl[1], br[0], br[1])
# if the 'q' key is pressed, stop the loop
elif key == ord("q"):
break
camera.release()
cv2.destroyAllWindows()
def drawing(x,y):
global paint_open
if paint_open == 0:
launchapp('kolourpaint')
paint_open = 1
py.dragTo(x,y)
def main():
root=tk.Tk()
bkgcolor='#D84315'
root.configure(background=bkgcolor)
label=tk.Label(root,text="Gesture Recognition Project",font=('arial black',12),fg="white",width=90,height=3,bg="purple")
label.pack()
frame1 = tk.Frame(root,bg=bkgcolor)
frame1.pack(padx=205,pady=25)
bframe1 = tk.Frame(root,bg=bkgcolor)
bframe1.pack(side=tk.BOTTOM,padx=205)
photo3 = tk.PhotoImage(file="3.png")
button2 = tk.Button(frame1, width=255, height=255, image=photo3,text="Slide Presenter",fg="purple",bg="white",command=func)
button2.pack(side=tk.LEFT,padx=25)
button2.image = photo1
# start the event loop
root.mainloop()
This question is a bit old but worth answering, since it comes up in searches. I experienced the same problem and eventually found an answer that worked. It seems hack-ish, but allows opencv to go through its processes to close a window. Opencv performs its processing during the waitKey(), so adding a few of those before and after the destroyallwindows() function did the trick.
In your code, where it says
cv2.destroyAllWindows()
... try this instead. It worked for me.
# All these waitkeys are a hack to get the OpenCV window to close
cv2.waitKey(1)
cv2.destroyAllWindows()
for i in range (1,5):
cv2.waitKey(1)
return
I'm not sure but cv may use tkinter to display windows so root.mainloop() may keep windows open. You can try to end root.mainloop() to close program and all windows.
import Tkinter as tk
import cv2
# create global value (with some value)
root = None
def func():
# inform function to use global variable instead of local one
global root
# ...
cv2.destroyAllWindows()
camera.release()
# close root window and leave mainloop()
root.destroy()
def main():
# inform function to use global variable instead of local one
global root
root = tk.Tk()
# ...
root.mainloop()
main()
Since a new window is opened upon calling destroyAllWindows() function, you need to press space-key to close the execution of the command.
This work for me
while True:
_, frame = cap.read()
cv2.imshow(windowName, frame)
keyCode = cv2.waitKey(1)
if cv2.getWindowProperty(windowName, cv2.WND_PROP_VISIBLE) <1:
break
cv2.destroyAllWindows()
from https://newbedev.com/closing-video-window-using-close-x-button-in-opencv-python

Categories