The issue to show the webcam in the window from pyqt5, it shows in the external window
we tried this code:
class FacialRecSt(QDialog):
def init(self):
super(FacialRecSt, self).init()
loadUi("FacialRecSetup.ui",self)
self.ExitFacialSetUp.clicked.connect(self.gotoExitFacialSetUp)
self.TakeMyAttendanceButton.clicked.connect(self.startVideo)
#FacialRecSt.displayImage()
now = QDate.currentDate()
current_date = now.toString('ddd dd MMMM yyyy') #format of date
current_time = datetime.datetime.now().strftime("%I:%M %p") #for time,p: pm or am
self.Date_Output.setText(current_date)
self.Time_Output.setText(current_time)
self.img = None
#exit
def gotoExitFacialSetUp(self):
widget.setCurrentIndex(widget.currentIndex()-14)
def startVideo(self):
path = 'Dataset'
images = []
classNames = []
myList = os.listdir(path)
print(myList)
for cl in myList:
curImg = cv2.imread(f'{path}/{cl}')
images.append(curImg)
classNames.append(os.path.splitext(cl)[0]) #to show only bame without .jpg
print(classNames)
self.timer = QTimer(self) # Create Timer
self.timer.timeout.connect(self.update_frame) # Connect timeout to the output function
self.timer.start(10) # emit the timeout() signal at x=40ms
#find encoding foe each image
def findEncodings(images):
encodeList = []
for img in images:
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
encode = face_recognition.face_encodings(img)[0]
encodeList.append(encode)
return encodeList
def mark_attendance(name):
#To not click the button multiple times
if self.TakeMyAttendanceButton.isChecked():
self.TakeMyAttendanceButton.setEnabled(False)
with open('attendanceName.csv', 'a') as f:
if (name != 'unknown'): #if name in database.
#if they press clicking take my attendance by mistake, default here is no
buttonReply = QMessageBox.question(self, 'Welcome ' + name, 'Are you pressing "Taking My Attendance"?' ,
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
#When Answer is yes
#if the button not clocked by mistake, answer yes
if buttonReply == QMessageBox.Yes:
date_time_string = datetime.datetime.now().strftime("%y/%m/%d %H:%M:%S")
f.writelines(f'\n{name},{date_time_string}')
self.TakeMyAttendanceButton.setChecked(False)
self.Name_Output.setText(name)
self.Time_Output = datetime.datetime.now()
self.TakeMyAttendanceButton.setEnabled(True)
# When answer is NO show:
else:
print('Button is Not clicked.')
self.TakeMyAttendanceButton.setEnabled(True)
#### FOR CAPTURING SCREEN RATHER THAN WEBCAM
# def captureScreen(bbox=(300,300,690+300,530+300)):
# capScr = np.array(ImageGrab.grab(bbox))
# capScr = cv2.cvtColor(capScr, cv2.COLOR_RGB2BGR)
# return capScr
encodeListKnown = findEncodings(images)
print('Encoding Complete')
cap = cv2.VideoCapture(0)
while True:
success, img = cap.read()
#img = cv2.captureScreen()
imgS = cv2.resize(img,(0,0),None,0.25,0.25)
imgS = cv2.cvtColor(imgS, cv2.COLOR_BGR2RGB)
facesCurFrame = face_recognition.face_locations(imgS) #find lcation of face even from multiple faces in image
encodesCurFrame = face_recognition.face_encodings(imgS,facesCurFrame)
#loop through all faces, zip to be in same loop
for encodeFace,faceLoc in zip(encodesCurFrame,facesCurFrame):
matches = face_recognition.compare_faces(encodeListKnown,encodeFace)
faceDis = face_recognition.face_distance(encodeListKnown,encodeFace)#face distance for each one, lowest distance is best match
#print(faceDis)
matchIndex = np.argmin(faceDis) #min distance in face
#name for the person
if matches[matchIndex]:
name = classNames[matchIndex].upper()
#print(name)
y1,x2,y2,x1 = faceLoc
y1, x2, y2, x1 = y1*4,x2*4,y2*4,x1*4
cv2.rectangle(img,(x1,y1),(x2,y2),(0,255,0),2) #....., color, thikness
cv2.rectangle(img,(x1,y2-35),(x2,y2),(0,255,0),cv2.FILLED)
cv2.putText(img,name,(x1+6,y2-6),cv2.FONT_HERSHEY_COMPLEX,1,(255,255,255),2)
mark_attendance(name)
#self.Label_Show_Image=cv2.imshow('att',img)
#######################################
def update_frame(self):
ret, self.img = self.cap.read()
self.displayImage(self.img, self.encodeList, self.classNames, 1)
def displayImage(self, img, encodeList, classNames, window=1):
"""
:param img: frame from camera
:param encodeList: known face encoding list
:param classNames: known face names
:param window: number of window
:return:
"""
img = cv2.resize(img, (640, 480))
try:
img = self.face_rec_(img, encodeList, classNames)
except Exception as e:
print(e)
qformat = QImage.Format_Indexed8
if len(img.shape) == 3:
if img.shape[2] == 4:
qformat = QImage.Format_RGBA8888
else:
qformat = QImage.Format_RGB888
outImage = QImage(img, img.shape[1], img.shape[0], img.strides[0], qformat)
outImage = outImage.rgbSwapped()
if window == 1:
self.Label_Show_Image.setPixmap(QPixmap.fromImage(outImage))
self.Label_Show_Image.setScaledContents(True)
Related
Here, I have a code that takes a video as input and let the user draw a ROI. Later the cropped video will be displayed. This code was originally taken from I would like to define a Region of Interest in a video and only process that area.
I have provided the code below.
Question: I would like to save the cropped video in .mp4 format. The video output shows only a 1kb file. Can you go through the code and suggest a solution?
NB: I went through answer provided at OpenCV video not getting saved. Still I have failed to figure out the error.
import numpy as np
import cv2
import matplotlib.pyplot as plt
ORIGINAL_WINDOW_TITLE = 'Original'
FIRST_FRAME_WINDOW_TITLE = 'First Frame'
DIFFERENCE_WINDOW_TITLE = 'Difference'
canvas = None
drawing = False # true if mouse is pressed
#Retrieve first frame
def initialize_camera(cap):
_, frame = cap.read()
return frame
# mouse callback function
def mouse_draw_rect(event,x,y,flags, params):
global drawing, canvas
if drawing:
canvas = params[0].copy()
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
params.append((x,y)) #Save first point
elif event == cv2.EVENT_MOUSEMOVE:
if drawing:
cv2.rectangle(canvas, params[1],(x,y),(0,255,0),2)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
params.append((x,y)) #Save second point
cv2.rectangle(canvas,params[1],params[2],(0,255,0),2)
def select_roi(frame):
global canvas
#here, it is the copy of the first frame.
canvas = frame.copy()
params = [frame]
ROI_SELECTION_WINDOW = 'Select ROI'
cv2.namedWindow(ROI_SELECTION_WINDOW)
cv2.setMouseCallback(ROI_SELECTION_WINDOW, mouse_draw_rect, params)
roi_selected = False
while True:
cv2.imshow(ROI_SELECTION_WINDOW, canvas)
key = cv2.waitKey(10)
#Press Enter to break the loop
if key == 13:
break;
cv2.destroyWindow(ROI_SELECTION_WINDOW)
roi_selected = (3 == len(params))
print(len(params))
if roi_selected:
p1 = params[1]
p2 = params[2]
if (p1[0] == p2[0]) and (p1[1] == p2[1]):
roi_selected = False
#Use whole frame if ROI has not been selected
if not roi_selected:
print('ROI Not Selected. Using Full Frame')
p1 = (0,0)
p2 = (frame.shape[1] - 1, frame.shape[0] -1)
return roi_selected, p1, p2
if __name__ == '__main__':
cap = cv2.VideoCapture(r'E:\cardiovascular\brad1low.mp4')
#Grab first frame
first_frame = initialize_camera(cap)
#Select ROI for processing. Hit Enter after drawing the rectangle to finalize selection
roi_selected, point1, point2 = select_roi(first_frame)
#Grab ROI of first frame
first_frame_roi = first_frame[point1[1]:point2[1], point1[0]:point2[0]]
print(f'first frame roi is {first_frame_roi}')
#An empty image of full size just for visualization of difference
difference_image_canvas = np.zeros_like(first_frame)
out = cv2.VideoWriter(r'E:\cardiovascular\filename2.mp4', cv2.VideoWriter_fourcc(*'MP4V'), int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), (int(first_frame_roi.shape[0]), (int(first_frame_roi.shape[1]))))
while cap.isOpened():
ret, frame = cap.read()
if ret:
#ROI of current frame
roi = frame[point1[1]:point2[1], point1[0]:point2[0]]
print(f'roi is {roi}')
cv2.imshow(DIFFERENCE_WINDOW_TITLE, roi)
out.write(roi)
key = cv2.waitKey(30) & 0xff
if key == 27:
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()
I have created application for video camera with PySimple GUI.
Though recording starts, I cannot open the recorded file.
Codes for recording is as follow:
elif Record:
cv2.destroyWindow('Camera View')
while True:
# get data
ret, frame = camera.read()
# date
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(frame,strftime("%Y-%m-%d-%H:%M:%S"),(10,30), font, 1,(255,255,255),2,cv2.LINE_AA)
cv2.imshow('Record Window', frame)
video.write(frame)
#RecordStop True
event, values = window.read(timeout=20)
if event == 'RecordStop':
break
cv2.destroyWindow('Record View')
CameraOn = True
Record = False
I think that "Camera App." window interupts the recording because I can successfuly record a video if I don't use GUI.
I would like to know how to change the code.
All the code is as follows.
import PySimpleGUI as sg
import cv2
import numpy as np
from time import strftime
windowname = "Camera View"
camera = cv2.VideoCapture(0)
# layout
sg.theme('BluePurple')
layout = [[sg.Text('Operation:'),sg.Text(size=(15,1), key='-OUTPUT-')],[sg.Button('CameraOn'), sg.Button('CameraOff'), sg.Button('Record'), sg.Button('RecordStop')]]
# Show Window
window = sg.Window('Camera App.',layout, location=(800, 400))
# Movie FIle
fps = int(camera.get(cv2.CAP_PROP_FPS)) # Get FPS
w = int(camera.get(cv2.CAP_PROP_FRAME_WIDTH)) # Get Width
h = int(camera.get(cv2.CAP_PROP_FRAME_HEIGHT)) # Get Height
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') # mp4
video = cv2.VideoWriter('video.mp4', fourcc, fps, (w, h)) # (File Name,fourcc, FPS, Size)
CameraOn = False
Record = False
# Event Loop
while True:
# Get Event
event, values = window.read(timeout=20)
# "CameraOn"
if event == 'CameraOn':
CameraOn = True
Record = False
# "CameraOff"
elif event == 'CameraOff' or event == sg.WIN_CLOSED:
CameraOn = False
Record = False
break
# "Record"
elif event == 'Record':
CameraOn = False
Record = True
# CameraOn True
elif CameraOn:
# get data
ret, frame = camera.read()
frame_num = camera.get(cv2.CAP_PROP_FRAME_COUNT)
# date
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(frame,strftime("%Y-%m-%d-%H:%M:%S"),(10,30), font, 1,(255,255,255),2,cv2.LINE_AA)
# show
cv2.imshow(windowname, frame)
# Record True
elif Record:
cv2.destroyWindow('Camera View')
while True:
# get data
ret, frame = camera.read()
# date
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(frame,strftime("%Y-%m-%d-%H:%M:%S"),(10,30), font, 1,(255,255,255),2,cv2.LINE_AA)
cv2.imshow('Record Window', frame)
video.write(frame)
#RecordStop True
event, values = window.read(timeout=20)
if event == 'RecordStop':
break
cv2.destroyWindow('Record View')
CameraOn = True
Record = False
cv2.destroyAllWindows()
print("Finish Program")
I'm detecting Unicode words on a starscape background. They all look a little like the example images below. I have a folder with 183 images, if any of those images are detected I want to click a button on the screen. If no images are detected, I want to repeat the process.
So far I've been having the most success with Template Matching. I load the images into an array, loop through the entire array and if anything returns a >90% match I click the button.
This however is returning a large number of false positives. To improve my detection I've tried;
Canny Edge detection
HSV Thresholding
MatchTemplate
SIFT and SURF
and, Brute-Force Matching with ORB Descriptors
The best results by a long shot have been with ORB, hands down, not even close.
I've followed this tutorial and all of the tutorials on opencv.org however I'm getting the following error what seems like fairly randomly. Usually it's when the background application image changes significantly but I've no idea why that would matter.
Traceback (most recent call last):
File "c:\Users\keypoint_detection_test1.py", line 63, in <module>
keypoint_detection(ships_to_avoid)
File "c:\Users\keypoint_detection_test1.py", line 39, in keypoint_detection
kp1, kp2, matches, match_points = objectToFind.match_keypoints(keypoint_image)
ValueError: too many values to unpack (expected 4)
What does this error mean and how do I fix it?
import cv2 as cv
import os
import glob
# Change the working directory to the folder this script is in.
os.chdir('C:\\Users\\')
avoid = glob.glob(r"C:\Users\*.png")
def loadImages(directory):
# Intialise empty array
image_list = []
# Add images to array
for i in directory:
img = cv.imread(i, cv.IMREAD_UNCHANGED)
image_list.append((img, i))
return image_list
# initialize the WindowCapture class
wincap = WindowCapture()
def keypoint_detection(image_list):
for i in image_list:
needle_img = i[0]
needle_name = i[1]
# load image to find
objectToFind = Vision(needle_img)
# get an updated image of the screen
keypoint_image = wincap.get_haystack()
# crop the image
x, w, y, h = [600,700,20,50]
keypoint_image = keypoint_image[y:y+h, x:x+w]
kp1, kp2, matches, match_points = objectToFind.match_keypoints(keypoint_image)
match_image = cv.drawMatches(objectToFind.needle_img, kp1, keypoint_image, kp2, matches, None)
if match_points:
# find the center point of all the matched features
center_point = objectToFind.centeroid(match_points)
# account for the width of the needle image that appears on the left
center_point[0] += objectToFind.needle_w
# drawn the found center point on the output image
match_image = objectToFind.draw_crosshairs(match_image, [center_point])
# move somewhere/do something
#py.moveTo(center_point)
# display the processed image
cv.imshow('Keypoint Search', match_image)
# press 'q' with the output window focused to exit.
if cv.waitKey(1) == ord('q'):
cv.destroyAllWindows()
while(True):
ships_to_avoid = loadImages(avoid)
keypoint_detection(ships_to_avoid)
class Vision:
# properties
needle_img = None
needle_w = 0
needle_h = 0
# constructor
def __init__(self, needle_img_path):
self.needle_img = needle_img_path
# Save the dimensions of the needle image
self.needle_w = self.needle_img.shape[1]
self.needle_h = self.needle_img.shape[0]
def match_keypoints(self, original_image, patch_size=32):
min_match_count = 35
orb = cv.ORB_create(edgeThreshold=0, patchSize=patch_size)
keypoints_needle, descriptors_needle = orb.detectAndCompute(self.needle_img, None)
orb2 = cv.ORB_create(edgeThreshold=0, patchSize=patch_size, nfeatures=2000)
keypoints_haystack, descriptors_haystack = orb2.detectAndCompute(original_image, None)
FLANN_INDEX_LSH = 6
index_params = dict(algorithm=FLANN_INDEX_LSH, table_number=6, key_size=12, multi_probe_level=1)
search_params = dict(checks=50)
try:
flann = cv.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(descriptors_needle, descriptors_haystack, k=2)
except cv.error:
return None, None, [], [], None
# store all the good matches as per Lowe's ratio test.
good = []
points = []
for pair in matches:
if len(pair) == 2:
if pair[0].distance < 0.7*pair[1].distance:
good.append(pair[0])
if len(good) > min_match_count:
print('match %03d, kp %03d' % (len(good), len(keypoints_needle)))
for match in good:
points.append(keypoints_haystack[match.trainIdx].pt)
return keypoints_needle, keypoints_haystack, good, points
class WindowCapture:
# properties
w = 0
h = 0
hwnd = None
cropped_x = 0
cropped_y = 0
offset_x = 0
offset_y = 0
# constructor
def __init__(self, window_name=None):
# find the handle for the window we want to capture.
# if no window name is given, capture the entire screen
if window_name is None:
self.hwnd = win32gui.GetDesktopWindow()
else:
self.hwnd = win32gui.FindWindow(None, window_name)
if not self.hwnd:
raise Exception('Window not found: {}'.format(window_name))
# get the window size
window_rect = win32gui.GetWindowRect(self.hwnd)
self.w = window_rect[2] - window_rect[0]
self.h = window_rect[3] - window_rect[1]
# account for the window border and titlebar and cut them off
border_pixels = 0
titlebar_pixels = 0
self.w = self.w - (border_pixels * 2)
self.h = self.h - titlebar_pixels - border_pixels
self.cropped_x = border_pixels
self.cropped_y = titlebar_pixels
self.offset_x = window_rect[0] + self.cropped_x
self.offset_y = window_rect[1] + self.cropped_y
def get_haystack(self):
# get the window image data
wDC = win32gui.GetWindowDC(self.hwnd)
dcObj = win32ui.CreateDCFromHandle(wDC)
cDC = dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, self.w, self.h)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0, 0), (self.w, self.h), dcObj, (self.cropped_x, self.cropped_y), win32con.SRCCOPY)
signedIntsArray = dataBitMap.GetBitmapBits(True)
img = np.fromstring(signedIntsArray, dtype='uint8')
img.shape = (self.h, self.w, 4)
# free resources
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(self.hwnd, wDC)
win32gui.DeleteObject(dataBitMap.GetHandle())
img = img[...,:3]
img = np.ascontiguousarray(img)
return img
In match_keypoints you have (at least) two return statements.
One of them, in the except block returns 5 elements , None, None, [], [], None.
The other returns 4 elements, return keypoints_needle, keypoints_haystack, good, points
Thus, whenever match_keypoints encounters cv.error in that try block, it will return 5 elements, which is one more than you attempt to dereference in the line that is failing: kp1, kp2, matches, match_points = objectToFind.match_keypoints(keypoint_image)
Too many values to unpack is the error that occurs when the returned tuple has more elements than the number of variables on the LHS of the assignment.
how can i control frames in opencv?
here you insert the url of a video in the internet/local and this streams it to you.but voice and video are not Coordinated.video is faster than voice :/
import cv2
import numpy as np
from ffpyplayer.player import MediaPlayer
def getVideoSource(source, width, height):
cap = cv2.VideoCapture(source)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
return cap
def main():
url=input('enter url: ')
sourcePath = url
camera = getVideoSource(sourcePath, 720, 480)
player = MediaPlayer(sourcePath)
while True:
ret, frame = camera.read()
audio_frame, val = player.get_frame()
if (ret == 0):
print("End of video")
break
frame = cv2.resize(frame, (720, 480))
cv2.imshow('Camera', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
if val != 'eof' and audio_frame is not None:
frame, t = audio_frame
print("Frame:" + str(frame) + " T: " + str(t))
camera.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
A slight modification of the answer by #furas:
player = MediaPlayer(video_path)
while True:
frame, val = player.get_frame()
if val == 'eof':
break # this is the difference
if frame is not None:
image, pts = frame
w, h = image.get_size()
# convert to array width, height
img = np.asarray(image.to_bytearray()[0]).reshape(h,w,3)
# convert RGB to BGR because `cv2` need it to display it
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
time.sleep(val)
cv2.imshow('video', img)
if cv2.waitKey(1) & 0xff == ord('q'):
break
cv2.destroyAllWindows()
player.close_player()
The difference is the explicit break once EOF is reached, which causes the program to terminate. To me, that's expected behavior, so I wanted to post this code in case someone wants that behavior as well.
It seems you can't control when to play audio because it uses SDL to play it in separated thread but get_frame() gives tuple (frame, val) and frame is (image, time_when_to_display_image) and you should use this time_when_to_display_image to control when to display image.
And all this code doesn't need cv2.VideoCapture() to get frame.
I use cv2 only to display it but you can use any GUI to create window to display it.
I use current_time to get next frame without using time.sleep() because video wasn't smooth.
BTW: You can use player.set_size(720, 480) to resize frame.
from ffpyplayer.player import MediaPlayer
import cv2
import numpy as np
import time
filename = 'video.mp4'
player = MediaPlayer(filename)
player.set_size(720, 480) # resize it
#player.set_size(400, 300)
start_time = time.time()
frame_time = start_time + 0
while True:
current_time = time.time()
# check if it is time to get next frame
if current_time >= frame_time:
# get next frame
frame, val = player.get_frame()
if val != 'eof' and frame is not None:
image, pts = frame
w, h = image.get_size()
# convert to array width, height
img = np.asarray(image.to_bytearray()[0]).reshape(h,w,3)
# convert RGB to BGR because `cv2` need it to display it
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
cv2.imshow('video', img)
frame_time = start_time + pts
if cv2.waitKey(1) & 0xff == ord('q'):
break
cv2.destroyAllWindows()
player.close_player()
EDIT: I found that get_frame() gives (frame, val) and this val can be used in time.sleep(val). And probably it should sleep before displaying frame, not after displaying it.
from ffpyplayer.player import MediaPlayer
import cv2
import numpy as np
import time
filename = 'video.mp4'
player = MediaPlayer(filename)
player.set_size(720, 480)
#player.set_size(400, 300)
while True:
frame, val = player.get_frame()
if val != 'eof' and frame is not None:
image, pts = frame
w, h = image.get_size()
# convert to array width, height
img = np.asarray(image.to_bytearray()[0]).reshape(h,w,3)
# convert RGB to BGR because `cv2` need it to display it
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
time.sleep(val)
cv2.imshow('video', img)
if cv2.waitKey(1) & 0xff == ord('q'):
break
cv2.destroyAllWindows()
player.close_player()
EDIT: Code using tkinter to display it.
from ffpyplayer.player import MediaPlayer
import tkinter as tk
from PIL import Image, ImageTk
import time
# -- functions ---
def update_frame():
global photo # solution for BUG in PhotoImage
frame, val = player.get_frame()
if val != 'eof' and frame is not None:
image, pts = frame
w, h = image.get_size()
data = image.to_bytearray()[0]
img = Image.frombytes("RGB", (w,h), bytes(data))
photo = ImageTk.PhotoImage(img)
time.sleep(val)
label['image'] = photo
root.after(1, update_frame) # again after `1ms` without blocking `mainloop()`
# --- main ---
filename = 'video.mp4'
player = MediaPlayer(filename)
player.set_size(720, 480)
#player.set_size(400, 300)
root = tk.Tk()
label = tk.Label(root)
label.pack()
root.bind('q', lambda event:root.destroy())
update_frame()
root.mainloop()
player.close_player()
im trying to make a color detection system with python opencv this is what i have done so far. im still new to python so please help me thank you
basically what should happen is that when the user opens this application the camera open and when he clicks anywhere on the window it will tell the name of the color
from tkinter import *
from tkinter import ttk
import cv2
import numpy as np
import webcolors
def click_event(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
blue = cap[y, x, 0]
green = cap[y, x, 1]
red = cap[y, x, 2]
font = cv2.FONT_HERSHEY_SIMPLEX
#colourcode = str(blue) + ", " + str(green) + ", " + str(red)
colourcode2 = (red, green, blue)
cv2.imshow('frame', frame)
def closest_colour(requested_colour):
min_colours = {}
for key, name in webcolors.css3_hex_to_names.items():
r_c, g_c, b_c = webcolors.hex_to_rgb(key)
rd = (r_c - requested_colour[0]) ** 2
gd = (g_c - requested_colour[1]) ** 2
bd = (b_c - requested_colour[2]) ** 2
min_colours[(rd + gd + bd)] = name
return min_colours[min(min_colours.keys())]
def get_colour_name(requested_colour):
try:
closest_name = actual_name = webcolors.rgb_to_name(requested_colour)
except ValueError:
closest_name = closest_colour(requested_colour)
actual_name = None
return actual_name, closest_name
#print(colourcode2)
requested_colour = colourcode2
actual_name, closest_name = get_colour_name(requested_colour)
#print("colour name:", closest_name)
cv2.putText(img, closest_name, (0, 50), font, 1, 255, 2)
cap = cv2.VideoCapture(0);
while True:
ret, frame = cap.read()
cv2.imshow('frame', frame)
if cv2.waitKey(40) == 27:
break
cv2.waitKey(0)
cv2.destroyAllWindows()
I don't know what is your problem but using your code I create version which works for me
I use cv2.setMouseCallback to assign your function to mouse click. It gets pixel from frame, not cap. Pixel is a list/tuple of (B,G,R) so I revere it list[::-1]. After I get name of color I assign it to external/global variable, not put on frame. In main loop I use this name to put on frame before it will display it.
I also use EVENT_LBUTTONUP to remove text when I release mouse button.
elif event == cv2.EVENT_LBUTTONUP:
closest_name = ''
If you remove above lines then it will keep text when you release mouse button.
import cv2
import webcolors
# --- functions ---
def closest_colour(requested_colour):
min_colours = {}
for key, name in webcolors.css3_hex_to_names.items():
r_c, g_c, b_c = webcolors.hex_to_rgb(key)
rd = (r_c - requested_colour[0]) ** 2
gd = (g_c - requested_colour[1]) ** 2
bd = (b_c - requested_colour[2]) ** 2
min_colours[(rd + gd + bd)] = name
return min_colours[min(min_colours.keys())]
def get_colour_name(requested_colour):
try:
closest_name = actual_name = webcolors.rgb_to_name(requested_colour)
except ValueError:
closest_name = closest_colour(requested_colour)
actual_name = None
return actual_name, closest_name
def click_event(event, x, y, flags, param):
global closest_name # inform function to assign to global/external variable instead of creating local one
if event == cv2.EVENT_LBUTTONDOWN:
#B, G, R = frame[x, y]
#colour = (R, G, B) # reverse values
colour = frame[y,x][::-1] # reverse values
actual_name, closest_name = get_colour_name(colour)
print(actual_name, closest_name)
elif event == cv2.EVENT_LBUTTONUP:
closest_name = ''
# --- main ---
font = cv2.FONT_HERSHEY_SIMPLEX
closest_name = '' # create global variable at start
cap = cv2.VideoCapture(0);
cv2.namedWindow('frame')
cv2.setMouseCallback('frame', click_event)
while True:
ret, frame = cap.read()
if closest_name:
#print(closest_name)
cv2.putText(frame, closest_name, (10, 30), font, 1, (255,255,255), 2)
cv2.imshow('frame', frame)
if cv2.waitKey(40) == 27:
break
cv2.waitKey(0)
cv2.destroyAllWindows()
cap.release()
In all GUIs when you press button then it creates single event EVENT_LBUTTONDOWN - it doesn't generate it again and again when you keep button pressed. So function click_event is executed only once and your version puts text only on one frame but few miliseconds later main loop gets new frame and displays it without text - so finally you don't see text on frame.