getting average RGB values of a drawn circle - python

I have written a code that draws circles over an image using mouse clicks. The radius and centre of the circles drawn are stored in a .txt file.
However, I want to add on another component into the text file;- the mean RGB value of the inside of the circles drawn. How do i go about doing that?
I've seen another qs where the author recommends using a mask. (RGB average of circles) Is it possible to do so without adding a mask?
import cv2
import numpy as np
import math
drawing = False
colours=[(255,0,0),(0,255,0),(0,0,255),(204,0,204),(0,155,255),(0,223,255),(238,220,130),
(255,79,79), (161,0,244),(32,178,170),(170,178,32)]
def draw_circle(event, x, y, flags, param):
global x1, y1, drawing, radius, num, img, img2,z,circleProps
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
x1, y1 = x, y
radius = int(math.hypot(x - x1, y - y1))
cv2.circle(img, (x1,y1), radius, (255, 0, 0), 1)
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
a, b = x, y
if a != x & b != y:
img = img2.copy()
radius = int(math.hypot(a - x1, b - y1))
cv2.circle(img, (x1,y1), radius, (255, 0, 0), 1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
num += 1
radius = int(math.hypot(x - x1, y - y1))
z = (z + 1) % (len(colours) - 1)
cv2.circle(img, (x1,y1), radius, colours[z], 1) #just need outer circle colour to be different
print("rad:",radius)
circleProps += "%d "%num + "%d "%x1 + "%d "%y1 + "%d \n"%radius
cv2.circle(img, (x1, y1), 1, (0, 255, 0), -1) #draws centre of circle
#font = cv2.FONT_HERSHEY_SIMPLEX
font = cv2.FONT_HERSHEY_PLAIN
cv2.putText(img, str(num), (x1 + radius, y1 + radius), font, 1, (200, 255, 155), 1, cv2.LINE_AA)
img2 = img.copy()
elif event == cv2.EVENT_RBUTTONUP:
pass
def handleKeyboard():
if cv2.waitKey(20) == 38:
print ('38')
if __name__ == "__main__":
num = 0
z = 0
windowName = 'Drawing'
circleProps ="Num | x1 | y1 | r \n"
img = cv2.imread('image.jpg', cv2.IMREAD_COLOR)
img2 = img.copy()
cv2.namedWindow(windowName)
cv2.setMouseCallback(windowName, draw_circle)
while (True):
cv2.imshow(windowName, img)
# handleKeyboard()
if cv2.waitKey(20) == 27:
text_file = open("Output.txt", "w") # create txt file
text_file.write(circleProps)
text_file.close()
break
elif cv2.waitKey(20) == 38:
print ('38')
cv2.destroyAllWindows()
EDIT:
I have just added these lines into the function and I am getting RGB values. However I am not sure if the values printed are right? Could someone clarify?
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
num += 1
radius = int(math.hypot(x - x1, y - y1))
z = (z + 1) % (len(colours) - 1)
circle_drawn=cv2.circle(img, (x1,y1), radius, colours[z], 1) #lines added
RGB=cv2.mean(circle_drawn) #lines added
print("RGB: ", RGB) #lines added
print("rad:",radius)
circleProps += "%d "%num + "%d "%x1 + "%d "%y1 + "%d \n"%radius
cv2.circle(img, (x1, y1), 1, (0, 255, 0), -1) #draws centre of circle
#font = cv2.FONT_HERSHEY_SIMPLEX
font = cv2.FONT_HERSHEY_PLAIN
cv2.putText(img, str(num), (x1 + radius, y1 + radius), font, 1, (200, 255, 155), 1, cv2.LINE_AA)
img2 = img.copy()

Related

OpenCV does not detect object if size of object is different from the target image

I am developing my computer vision skills So I made a script to detect things inside the screen
We have this script I've put the disclosure image
The problem is that when you zoom in and out, it is not detected
import keyboard
import mss
import cv2
import numpy
from time import time, sleep
import pyautogui
pyautogui.PAUSE = 0
sct = mss.mss()
dimensions_left = {'left': 0,'top': 0,'width': 2560,'height': 1440}
print("Press 's' to start playing.")
print("Once started press 'p' to quit.")
keyboard.wait('s')
detect = cv2.imread('scend.png', cv2.COLOR_RGB2BGR)
w = detect.shape[1]
h = detect.shape[0]
ww , hh = int(w/2),int(h/2)
fps_time = time()
while True:
im = numpy.array(sct.grab(dimensions_left))
im = numpy.flip(im[9:, 9:, :1], 2) # 1
im = cv2.resize(im, (1000, 500))
im = cv2.cvtColor(im, cv2.COLOR_RGB2BGR)
result = cv2.matchTemplate(im, detect, cv2.TM_CCOEFF_NORMED)
threshold = .4
yloc, xloc = numpy.where(result >= threshold)
rectangles = []
for (x, y) in zip(xloc, yloc):
rectangles.append([int(x), int(y), int(w), int(h)])
rectangles.append([int(x), int(y), int(w), int(h)])
rectangles, weights = cv2.groupRectangles(rectangles, 1, 0.2)
for (x, y, w, h) in rectangles:
cv2.rectangle(im, (x, y), (x + w, y + h), (0, 255, 255), 2)
cv2.rectangle(im, (x + ww, y + hh), (x + w - ww, y + h - hh), (0, 0, 255), 5)
# pyautogui.moveTo(x, y, 0)
cv2.imshow('Screen Shot', im)
cv2.waitKey(1)
if keyboard.is_pressed('p'):
break
print('FPS: {}'.format(1 / (time() - fps_time)))
fps_time = time()

How to create a meter based on model's probability in Python OpenCV

I have this simple Python code that makes predictions on the emotions of the face (refer to here in case you need to run it), whether the person is happy, sad, etc. It uses cv2 and Keras. Now, I would like to visualize and place a meter on the frame based on the probability of each frame (prob value below which is a percentage). How can I do that?
Something like this. Don't worry about the colors for now.
cap = cv2.VideoCapture(1)
canvasImage = cv2.imread("fg2.png")
x0, x1 = 330, 1290
y0, y1 = 155, 700
prediction_history = []
LOOKBACK = 5 # how far you want to look back
counter = 0
while True:
# Find haar cascade to draw bounding box around face
ret, frame = cap.read()
frame=cv2.flip(frame,3)
if not ret:
break
facecasc = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = facecasc.detectMultiScale(gray,scaleFactor=1.3, minNeighbors=5)
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y-50), (x+w, y+h+10), (255, 0, 0), 2)
roi_gray = gray[y:y + h, x:x + w]
cropped_img = np.expand_dims(np.expand_dims(cv2.resize(roi_gray, (48, 48)), -1), 0)
prediction = model.predict(cropped_img)
maxindex = int(np.argmax(prediction))
text = emotion_dict[maxindex]
prob = round(prediction[0][3]*100, 2)
prediction_history.append(maxindex)
most_common_index = max(set(prediction_history[-LOOKBACK:][::-1]), key = prediction_history.count)
text = emotion_dict[most_common_index]
#if ("Sad" in text) or ("Angry" in text) or ("Disgusted" in text):
# text = "Sad"
if ("Happy" in text) or ("Sad" in text) :
cv2.putText(frame, text+": "+str(prob), (x+20, y-60), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA)
dim = (800,480)
frame_shrunk = cv2.resize(frame, (x1 - x0, y1 - y0))
canvasImage[y0:y1, x0:x1] = frame_shrunk
#cv2.imshow('Video', cv2.resize(frame,dim,interpolation = cv2.INTER_CUBIC))
cv2.imshow('Demo', canvasImage)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
There is no built in function in OpenCV for drawing meters, here is a helper function that you can use to draw a meter over an image:
def draw_indicator(img, percentage):
def percentage_to_color(p):
return 0, 255 * p, 255 - (255 * p)
# config
levels = 10
indicator_width = 80
indicator_height = 220
level_width = indicator_width - 20
level_height = int((indicator_height - 20) / levels - 5)
# draw
img_levels = int(percentage * levels)
cv2.rectangle(img, (10, img.shape[0] - (indicator_height + 10)), (10 + indicator_width, img.shape[0] - 10), (0, 0, 0), cv2.FILLED)
for i in range(img_levels):
level_y_b = int(img.shape[0] - (20 + i * (level_height + 5)))
cv2.rectangle(img, (20, level_y_b - level_height), (20 + level_width, level_y_b), percentage_to_color(i / levels), cv2.FILLED)
# test code
img = cv2.imread('a.jpg')
draw_indicator(img, 0.7)
cv2.imshow("test", img)
cv2.waitKey(10000)

List index out of range in function

I'm new to this and I tried googling but
I can't seem to fix this error inside "fingersUp" function.
Basically, each part of a finger has indexes and this function checks if the thumb finger is up based on these indexes. Each finger has 4 points.
I'm using PyCharm and Python 3.8, if that helps.
if self.lmList[self.tipIds[0]][1] > self.lmList[self.tipIds[0] - 1][1]: IndexError: list index out of range
Here's the full code:
import cv2
import mediapipe as mp
import time
import math
import numpy as np
class handDetector():
def __init__(self, mode=False, maxHands=2, detectionCon=0.5, trackCon=0.5):
self.mode = mode
self.maxHands = maxHands
self.detectionCon = detectionCon
self.trackCon = trackCon
self.mpHands = mp.solutions.hands
self.hands = self.mpHands.Hands(self.mode, self.maxHands,
self.detectionCon, self.trackCon)
self.mpDraw = mp.solutions.drawing_utils
self.tipIds = [4, 8, 12, 16, 20]
def findHands(self, img, draw=True):
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
self.results = self.hands.process(imgRGB)
# print(results.multi_hand_landmarks)
if self.results.multi_hand_landmarks:
for handLms in self.results.multi_hand_landmarks:
if draw:
self.mpDraw.draw_landmarks(img, handLms,
self.mpHands.HAND_CONNECTIONS)
return img
def findPosition(self, img, handNo=0, draw=True):
xList = []
yList = []
bbox = []
self.lmList = []
if self.results.multi_hand_landmarks:
myHand = self.results.multi_hand_landmarks[handNo]
for id, lm in enumerate(myHand.landmark):
# print(id, lm)
h, w, c = img.shape
cx, cy = int(lm.x * w), int(lm.y * h)
xList.append(cx)
yList.append(cy)
# print(id, cx, cy)
self.lmList.append([id, cx, cy])
if draw:
cv2.circle(img, (cx, cy), 5, (255, 0, 255), cv2.FILLED)
xmin, xmax = min(xList), max(xList)
ymin, ymax = min(yList), max(yList)
bbox = xmin, ymin, xmax, ymax
if draw:
cv2.rectangle(img, (xmin - 20, ymin - 20), (xmax + 20, ymax + 20),
(0, 255, 0), 2)
return self.lmList, bbox
def fingersUp(self):
fingers = []
# Thumb
if self.lmList[self.tipIds[0]][1] > self.lmList[self.tipIds[0] - 1][1]:
fingers.append(1)
else:
fingers.append(0)
# Fingers
for id in range(1, 5):
if self.lmList[self.tipIds[id]][2] < self.lmList[self.tipIds[id] - 2][2]:
fingers.append(1)
else:
fingers.append(0)
# totalFingers = fingers.count(1)
return fingers
def findDistance(self, p1, p2, img, draw=True,r=15, t=3):
x1, y1 = self.lmList[p1][1:]
x2, y2 = self.lmList[p2][1:]
cx, cy = (x1 + x2) // 2, (y1 + y2) // 2
if draw:
cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), t)
cv2.circle(img, (x1, y1), r, (255, 0, 255), cv2.FILLED)
cv2.circle(img, (x2, y2), r, (255, 0, 255), cv2.FILLED)
cv2.circle(img, (cx, cy), r, (0, 0, 255), cv2.FILLED)
length = math.hypot(x2 - x1, y2 - y1)
return length, img, [x1, y1, x2, y2, cx, cy]
def main():
pTime = 0
cTime = 0
cap = cv2.VideoCapture(0)
detector = handDetector()
while True:
success, img = cap.read()
img = detector.findHands(img)
lmList, bbox = detector.findPosition(img)
if len(lmList) != 0:
cTime = time.time()
fps = 1 / (cTime - pTime)
pTime = cTime
cv2.putText(img, str(int(fps)), (10, 70), cv2.FONT_HERSHEY_PLAIN, 3,
(255, 0, 255), 3)
cv2.imshow("Image", img)
cv2.waitKey(1)
if __name__ == "__main_":
main()
def fingersUp(self):
fingers = []
if len(self.lmList):
if self.lmList[self.tipIds[0]][1] > self.lmList[self.tipIds[0]-1][1]:
fingers.append(1)
else:
fingers.append(0)
for id in range(1,5):
if self.lmList[self.tipIds[id]][2]< self.lmList[self.tipIds[id]-2][2]:
fingers.append(1)
else:
fingers.append(0)
else:
fingers = [0,0,0,0,0]
return fingers
I had this same issue. Once adding Try: Except: around the if else statements in the fingersUp function I had no issue. The error is there because the fuction is being run even when your hands are off the screen.
Try:
if self.lmList[self.tipIds[0]][1] > self.lmList[self.tipIds[0] - 1][1]:
fingers.append(1)
else:
fingers.append(0)
Except:
fingers.append(0)
Try, this line:
the brackets aren't placed right that is why it shows the error.
if (self.lmList[self.tipIds[0][1]]
enter image description here
1.Indentation
2. Missing "_ "

Create Mask Inside ROI selection

Hi I am trying to make the eyes that is circled to be white. I know we cant delete the eyes so i wanted to mask it, but i couldnt figure out a way. Below is my code.
import cv2
import os
cascPathface = os.path.dirname(
cv2.__file__) + "/data/haarcascade_frontalface_alt2.xml"
cascPatheyes = os.path.dirname(
cv2.__file__) + "/data/haarcascade_eye_tree_eyeglasses.xml"
faceCascade = cv2.CascadeClassifier(cascPathface)
eyeCascade = cv2.CascadeClassifier(cascPatheyes)
while True:
img = cv2.imread('man1.png')
newImg = cv2.resize(img, (600,600))
gray = cv2.cvtColor(newImg, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(60, 60),
flags=cv2.CASCADE_SCALE_IMAGE)
for (x,y,w,h) in faces:
cv2.rectangle(newImg, (x, y), (x + w, y + h),(0,255,0), 2)
faceROI = newImg[y:y+h,x:x+w]
eyes = eyeCascade.detectMultiScale(faceROI)
for (x2, y2, w2, h2) in eyes:
eye_center = (x + x2 + w2 // 2, y + y2 + h2 // 2)
radius = int(round((w2 + h2) * 0.25))
frame = cv2.circle(newImg, eye_center, radius, (255, 0, 0), 4)
# Display the resulting frame
cv2.imshow('Image', newImg)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
last = cv2.imwrite('faces_detected.png', faceROI)
cv2.destroyAllWindows()
This is the image where i want the eyes to be white:
In order to mask the eyes, change the thickness parameter in the cv2.circle method to -1. That will fill the circle with the specified color.
Change the code from frame = cv2.circle(newImg, eye_center, radius, (255, 0, 0), 4) to frame = cv2.circle(newImg, eye_center, radius, (255, 0, 0), -1).
Refer: https://www.geeksforgeeks.org/python-opencv-cv2-circle-method/
Kindly do upvote the solution, if you find it helpful.

Display present coordinate Circle instead of all the point using opencv

I am trying to draw a circle a present coordinate when the mouse moves from one place to another in OpenCV screen
Right now I am able to see all the circle where the mouse has been moved from one place to another as mentioned below in the snap
But I need to display only one circle(present coordinate) while using EVENT_MOUSEMOVE in mouse events as mentioned in snapshot
mentioned below is my code
import cv2
import numpy as np
import math
drawing = False
def draw_circle(event, x, y, flags, param):
global x1, y1, drawing, radius, num, img, img2
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
num += 1
x1, y1 = x, y
radius = int(math.sqrt((x - x1)**2 + (y - y1)**2))
print(radius)
cv2.circle(img, (x1,y1), radius, (255, 0, 0), 1)
if event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
radius = 5
cv2.circle(img, (x, y), radius, (0, 0, 255), -1)
if event == cv2.EVENT_LBUTTONUP:
#drawing = False
num += 1
radius = int(math.sqrt((x - x1)**2 + (y - y1)**2))
print(radius)
cv2.circle(img, (x1,y1), radius, (255, 0, 255), 1)
if __name__ == "__main__":
num = 0
windowName = 'Drawing'
img = np.zeros((500, 500, 3), np.uint8)
cv2.namedWindow(windowName)
cv2.setMouseCallback(windowName, draw_circle)
while (True):
cv2.imshow(windowName, img)
if cv2.waitKey(20) == 27:
break
cv2.destroyAllWindows()
Suggestions will be very helpful

Categories

Resources