I'm attempting to create a programĀ in which my code analyses a video from my security camera and locates the cars that have been spotted. I've figured out how to find the cars and draw red rectangles around them, but I'd like to add a condition that only draws boxes if there are more than 5 cars detected. However, I am unable to do so due to the presence of arrays. How would I go about fixing this code?
import cv2
classifier_file = 'cars.xml'
car_tracker = cv2.CascadeClassifier(classifier_file)
video = cv2.VideoCapture("footage.mp4")
while True:
(read_successful, frame) = video.read()
if read_successful:
grayscaled_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
else:
break
cars = car_tracker.detectMultiScale(grayscaled_frame)
if cars > 4:
for (x, y, w, h) in cars:
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)
cv2.imshow('Car Detector', frame)
cv2.waitKey(0)
By the way, I am using an anaconda environment along with python 3.8.8
You have an array of detections.
All you need is to call len() on the array to get the number of elements. This is a built-in function of Python.
cars = car_tracker.detectMultiScale(grayscaled_frame)
if len(cars) >= 5:
for (x, y, w, h) in cars:
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)
No need for any other libraries.
Here is one example using a different technique, in this case you can use cvlib it has a class object_detection to detect multiple classes. This uses the yolov4 weights, you will be capable of detect any car in the road or in this case from one webcam, only make sure that the car are ahead the camera not in 2d position.
import cv2
import matplotlib.pyplot as plt
# pip install cvlib
import cvlib as cv
from cvlib.object_detection import draw_bbox
im = cv2.imread('cars3.jpg')
#cv2.imshow("cars", im)
#cv2.waitKey(0)
bbox, label, conf = cv.detect_common_objects(im)
#yolov4 weights will be downloaded. Check: C:\Users\USER_NAME\.cvlib\object_detection\yolo
# if the download was not successful delete yolo folder and try again, it will be downloaded again
# after download the weights keep running the script it will say 0 cars, then close Anaconda spyder anda reopen it and try again.
#get bbox
output_image_with_bbox = draw_bbox(im, bbox, label, conf)
number_cars = label.count('car')
if number_cars > 5:
print('Number of cars in the image is: '+ str(number_cars))
plt.imshow(output_image_with_bbox)
plt.show()
else:
print('Number of cars in the image is: '+ str(number_cars))
plt.imshow(im)
plt.show()
output:
Greetings.
Related
ive been trying to use a script with cv2 and numpy to search an image for an icon, th start button for a stress test software, and that all works fine but it doesnt work together with any mouse movement packages, ive tried mouse, pyautogui, autoit and a few more with no results. the mouse movement works if i put it before the cv2 image recognition script but that wont work cause i need the coordinates.
P.S. 100, 500 is not the coordinates i want to move to, i want to move to the "coords" variable which should be equal to (pt[0] + w, pt[1] + h)
import cv2
import numpy as np
#import pyautogui
import time
import win32api
import pydirectinput
def movedamnyou():
pydirectinput.moveTo(100, 500)
#open OCCT
win32api.ShellExecute(0, "open", "D:\AppData\OCCT.exe", None, ".", 0)
#wait for program to open
time.sleep(20)
#classifier
#take screenshot
#im2 = pyautogui.screenshot('scrn.png')
# Read the main image
img_rgb = cv2.imread('scrn.png')
# Convert it to grayscale
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
# Read the template
template = cv2.imread('OCCTico.png', 0)
# Store width and height of template in w and h
w, h = template.shape[::-1]
# Perform match operations.
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
# Specify a threshold
threshold = 0.8
# Store the coordinates of matched area in a numpy array
loc = np.where(res >= threshold)
# Draw a rectangle around the matched region.
for pt in zip(*loc[::-1]):
cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0, 255, 255), 2)
# Show the final image with the matched area.
cv2.imshow('Detected', img_rgb)
#print the output position
coords = (pt[0] + w, pt[1] + h)
pydirectinput.moveTo(100, 500)
import pyautogui
pyautogui.moveTo(coords[0], coords[1])
I'm working on a project which uses openCV to detect a blue LED and obtain its x and y co-ords. So far, i have everything working however i can't seem to find any successful way of using the co-ordinates to move the cursor in the same way you can with a physical mouse.
I have tried using the python mouse module and pynput but they both have the same issue which is that the "press" feature is very inconsistent in how it works.
What i want to be able to do is for the LED to always be detected as a single click unless it is held in which case it should drag.
The problem is, dragging only works on some windows like file explorer and doesnt work on VScode or Chrome. Also i cant draw smooth lines using the press function as it only draws straight lines.
The only way i can think of doing something like this would be to draw small straight lines in regular intervals in order to form a smooth line but i'm unsure of how something like this would be done
Maybe there is a module that already does this but i cant seem to find anything on the subject. Most questions asked here are about automating the mouse events but thats not what im after.
The code i have so far is as follow:
from cv2 import warpPerspective
from LScalibrate import warpImage
import cv2
from ast import literal_eval
import numpy as np
import mouse
def start(root, pointsstr, maskparamsmalformed, width, height):
points = literal_eval(pointsstr)
maskparamsstr = ''.join([letter for letter in maskparamsmalformed if letter not in("array()")])
maskparams = literal_eval(maskparamsstr)
lower, upper = np.array(maskparams[0]), np.array(maskparams[1])
root.withdraw()
cap = cv2.VideoCapture(0)
cap.set(15, 3) # may have to change the 2nd arg. Only supported for some cameras. Testing with droidcam therefore cannot use this myself
mat = warpImage(cap, points)
while True:
check, frame = cap.read()
if not check:
break
frame = warpPerspective(frame, mat, (1000, 1000))
hsvimg = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
maskedimg = cv2.inRange(hsvimg, lower, upper)
image = cv2.bitwise_and(frame, frame, mask=maskedimg)
contours, rel = cv2.findContours(maskedimg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
pts = None
contourpts = []
if len(contours) != 0:
for contour in contours:
if cv2.contourArea(contour) > 10:
x, y, w, h = cv2.boundingRect(contour)
x = (x+(x+w))//2
y = (y+(y+h))//2
pts = (x, y)
contourpts.append(pts)
check = set(contourpts)
if len(check) > 1:
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5,5), 0)
minv, maxv, minl, maxl = cv2.minMaxLoc(gray)
pts = maxl
if pts is not None:
controlCursor(pts, width, height)
cv2.circle(frame, pts, 3, (0, 0, 255), -1)
else:
mouse.release("left")
cv2.imshow("win", frame)
if cv2.waitKey(1) & 0xFF == 27:
break
cap.release()
cv2.destroyAllWindows()
root.deiconify()
def minContour(contours):
return sorted(contours, key=cv2.contourArea, reverse=False)[0]
def controlCursor(pos, w, h):
print(pos)
print(w, h)
x = (pos[0]/1000)*w
y = (pos[1]/1000)*h
print(x, y)
mouse.move(x, y, True)
mouse.press("left")
I have included a video showing how it's currently working and all the program code if needed:
Video: https://youtu.be/Q9tOIyy_tsE
Github (all code): https://github.com/ImaadNisar/Lightscreen-Touchscreen-Detection
Thanks!
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
for a university project I am programming a face mask recognition. For detecting faces, I use the cv2.CascadeClassifier('face_detector.xml'). As I noticed, this program is taking up way too much of the CPU resulting in a heavily disordered video stream frame rate.
I am running the code on a MacBook Air with a 1.6Hz Dual Core (Intel Core i5).
Can someone explain what I can change to make it smoother? Or maybe recommend another face detection?
Here is my code:
import numpy as np
import os
import tensorflow as tf
import cv2
from matplotlib.pyplot import gray
# Disable tensorflow compilation warnings
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import cv2
# Load the cascade
face_cascade = cv2.CascadeClassifier('face_detector.xml')
# To capture video from webcam.
cap = cv2.VideoCapture(0)
# To use a video file as input
# cap = cv2.VideoCapture('filename.mp4')
model = tf.keras.models.load_model('checkpoint19.ckpt')
i = 0
while True:
# Read the frame
_, img = cap.read()
# Detect the faces
faces = face_cascade.detectMultiScale(img, 1.3, 4)
# save each frame as image with PNG format
image = cv2.imwrite('database/{index}.png'.format(index=i), img)
i += 1
# cut out the fragment in the box of the image
# Draw the rectangle around each face
for (x, y, w, h) in faces:
crop_img = img[y:y + h, x:x + w]
resizedImg = cv2.resize(crop_img, (224, 224))
gray = cv2.cvtColor(resizedImg, cv2.COLOR_BGR2GRAY)
imgArrNew = gray.reshape(1, 224, 224, 1)
prediction = model.predict(imgArrNew)
print(prediction)
label = np.argmax(prediction)
print(label)
# font
font = cv2.FONT_HERSHEY_SIMPLEX
# org
for (x, y, w, h) in faces:
org = (x, y+h+30)
# fontScale
fontScale = 1
# Blue color in BGR
color = (255, 0, 0)
# Line thickness of 2 px
thickness = 2
# output the predicted label/sign on the live-stream frame
if label == 0:
color = (0,0,225)
label_out = "Mask off"
if label == 1:
color = (50,205,50)
label_out = "Mask on"
if label == 2:
color = (0,255,225)
label_out = "incorrect Mask"
cv2.rectangle(img, (x, y), (x + w, y + h), color, 2)
image1 = cv2.putText(img, label_out, org, font,
fontScale, color, thickness, cv2.LINE_AA)
# Display
cv2.imshow('Face_Regonition', img)
# Stop if escape key is pressed
k = cv2.waitKey(30) & 0xff
if k == 27:
break
# Release the VideoCapture object
cap.release()
Thanks for your help :)
haar cascaded classifier is slow. . To do detection in every single frame is hard for low-end computing devices.
The easiest way is to use a lower resolution image or lower FPS. But it will appear to be cheap
The better way is to use a detection and tracking framework where detection happens at a 1hz interval at a new thread and tracking can happen at 30hz, which human eye cant tell the difference.
For detection of face, you can choose any method such as hear, HOG, CNN and put it in a new thread. In the main tracking thread (which can run in real time) update the model and predict the bounding box and display it.
You may look for the tracking from here. I suggest KCF based method for it is fast and reliable.
https://www.pyimagesearch.com/2018/07/30/opencv-object-tracking/
Just put the detection box rect as input rect box for the tracking. THen it should work directly.
Can any one give an example of edge box detection algorithm to generate proposals for object detection using open cv.
We can get the details from https://docs.opencv.org/3.4.0/d4/d0d/group__ximgproc__edgeboxes.html
Yes. First you will need to download the model file that is used for Edge Boxes here. Once you do that, the following code below (taken from their Github) can be used as an example for running the Edge Boxes algorithm. In short, put the code below into a separate file called edgeboxes_demo.py, then in the terminal type in:
python model.yml.gz image_file
model.yml.gz is the model that you saved from the link above which I assume is in the same directory where the code is. image_file is the path to the image you want to use for testing the algorithm. The code will run the Edge Boxes algorithm then draw the detected boxes on the image in green:
import cv2 as cv
import numpy as np
import sys
if __name__ == '__main__':
model = sys.argv[1]
im = cv.imread(sys.argv[2])
edge_detection = cv.ximgproc.createStructuredEdgeDetection(model)
rgb_im = cv.cvtColor(im, cv.COLOR_BGR2RGB)
edges = edge_detection.detectEdges(np.float32(rgb_im) / 255.0)
orimap = edge_detection.computeOrientation(edges)
edges = edge_detection.edgesNms(edges, orimap)
edge_boxes = cv.ximgproc.createEdgeBoxes()
edge_boxes.setMaxBoxes(30)
boxes = edge_boxes.getBoundingBoxes(edges, orimap)
for b in boxes:
x, y, w, h = b
cv.rectangle(im, (x, y), (x+w, y+h), (0, 255, 0), 1, cv.LINE_AA)
cv.imshow("edges", edges)
cv.imshow("edgeboxes", im)
cv.waitKey(0)
cv.destroyAllWindows()
Test Image
Result
Win 10 x64, Python 2.7, Spyder IDE
I'm using some code from Adrian Rosebrock's OpenCV blog...
import pyzbar
import cv2
# load the input image
image = cv2.imread("barcode_example.png")
# find the barcodes in the image and decode each of the barcodes
barcodes = pyzbar.pyzbar.decode(image)
# loop over the detected barcodes
for barcode in barcodes:
# extract the bounding box location of the barcode and draw the
# bounding box surrounding the barcode on the image
(x, y, w, h) = barcode.rect
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
# the barcode data is a bytes object so if we want to draw it on
# our output image we need to convert it to a string first
barcodeData = barcode.data.decode("utf-8")
barcodeType = barcode.type
# draw the barcode data and barcode type on the image
text = "{} ({})".format(barcodeData, barcodeType)
cv2.putText(image, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX,
0.5, (0, 0, 255), 2)
# show the output image
cv2.imshow("Image", image)
cv2.waitKey(0)
I keep getting the following error...
AttributeError: 'module' object has no attribute 'pyzbar'
Yet when I check the module in Spyder it does indeed have said artibute...
I've tried running from the command line with the same result.
I have also checked to see if my installation of zbar is working & it is with no problems
Is this an issue with the Python bindings or something really obvious?
Try:
import pyzbar.pyzbar as pyzbar
Works for me.