Capture what is in a rectangle of a numpy array - python

This might sound obvious to some of you but I was trying to figure out how to capture only what is in a rectangle.
The below code, uses dlib face detection and draws a bounding box around a detected face.
cv2.rectangle(img,(det.left(), det.top()), (det.right(), det.bottom()), color_green, line_width)
What I am struggling with is how to capture/ view only what is within the rectangle.
So in this example I only want to see what is in (det.left(), det.top()), (det.right(), det.bottom())
import sys
import dlib
import cv2
detector = dlib.get_frontal_face_detector()
cam = cv2.VideoCapture(1)
color_green = (0,255,0)
line_width = 3
while True:
ret_val, img = cam.read()
rgb_image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
dets = detector(rgb_image)
for det in dets:
cv2.rectangle(img,(det.left(), det.top()), (det.right(), det.bottom()), color_green, line_width)
cv2.imshow('my webcam', img)
if cv2.waitKey(1) == 27:
break # esc to quit
cv2.destroyAllWindows()

You can try to implement cropping with numpy slicing.
For a rectangle drawn by:
cv2.rectangle(img,(left,top), (right,bottom), color_green, line_width)
You can try cropping as:
new_img = img[top:bottom,left:right,:]

to show only the parts that are within the detected boxes you'd want to either black out what's outside the dets (which I find almost impossible) or you could simply draw the desired parts on a black canvas instead
this is why I start here with a black canvas
import sys
import dlib
import cv2
import numpy as np
detector = dlib.get_frontal_face_detector()
cam = cv2.VideoCapture(1)
color_green = (0, 255, 0)
line_width = 3
while True:
ret_val, img = cam.read()
# get image dims to creat a black canvas of the same size
# img shape is (rows, cols, c) or (h, w, c)
img_h, img_w , _ = img.shape # c = 3 assuming it's a color iamge
# this will act as our black background / canvas
black_tmp = np.zeros((img_h, img_w, 3), dtype=int)
rgb_image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
dets = detector(rgb_image)
for det in dets:
# det cy -> left , top | x2y2 -> right bottom
x , y, x2,y2 = det.left(), det.top(), det.right(), det.bottom()
# copy the pixels in the desired area to your black background
black_tmp [y:y2, x:x2, ::] = img[y:y2, x:x2, ::]
# maybe draw the rectangle on the new image too
cv2.rectangle(black_tmp,(det.left(), det.top()), (det.right(), det.bottom()), color_green, line_width)
cv2.imshow('my webcam', black_tmp)
if cv2.waitKey(1) == 27:
break # esc to quit
cv2.destroyAllWindows()
I've tried to only minimally edit your code
here's the np.zeros docs in case you need it
I hope this helps, if I missed any detail you need please feel free to point it out

Related

detect moving object with opencv and python

i found very interesting article about detection of moving objects, here is correspondng link :Detection of moving object
and also corresponding article : Article about object detection
i followed code and try to implement my self, here is corresponding code :
import cv2
import numpy as np
import matplotlib.pyplot as plt
from Background_Image_Creation import get_background
cap =cv2.VideoCapture("video_1.mp4")
#print(cap.get(cv2.CAP_PROP_FRAME_COUNT))
#print(cap.get(cv2.CAP_PROP_FPS))
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
save_name = "Result.mp4"
# define codec and create VideoWriter object
out = cv2.VideoWriter(save_name,cv2.VideoWriter_fourcc(*'mp4v'), 10, (frame_width, frame_height))
background_frame =get_background("video_1.mp4")
background = cv2.cvtColor(background_frame, cv2.COLOR_BGR2GRAY)
print(background.shape)
frame_count =0
consecutive_frame=8
#frame_diff_list =[]
while cap.isOpened():
ret,frame =cap.read()
print(ret)
print(frame.shape)
if ret==True:
frame_count+=1
orig_frame =frame.copy()
gray =cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
if frame_count % consecutive_frame == 0 or frame_count == 1:
frame_diff_list =[]
frame_diff = cv2.absdiff(gray, background)
ret, thresh = cv2.threshold(frame_diff, 50, 255, cv2.THRESH_BINARY)
dilate_frame = cv2.dilate(thresh, None, iterations=2)
frame_diff_list.append(dilate_frame)
print(frame_diff_list)
if len(frame_diff_list) == consecutive_frame:
# add all the frames in the `frame_diff_list`
sum_frames = sum(frame_diff_list)
print(sum_frames)
# find the contours around the white segmented areas
contours, hierarchy = cv2.findContours(sum_frames, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# draw the contours, not strictly necessary
for i, cnt in enumerate(contours):
cv2.drawContours(frame, contours, i, (0, 0, 255), 3)
for contour in contours:
# continue through the loop if contour area is less than 500...
# ... helps in removing noise detection
if cv2.contourArea(contour) < 500:
continue
# get the xmin, ymin, width, and height coordinates from the contours
(x, y, w, h) = cv2.boundingRect(contour)
# draw the bounding boxes
cv2.rectangle(orig_frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow('Detected Objects', orig_frame)
out.write(orig_frame)
if cv2.waitKey(100) & 0xFF == ord('q'):
break
else:
break
cap.release()
cv2.destroyAllWindows()
code for background frame creation is also presented :
import numpy as np
import cv2
import matplotlib.pyplot as plt
def get_background(path):
cap =cv2.VideoCapture(path)
frame_indices =cap.get(cv2.CAP_PROP_FRAME_COUNT)*np.random.uniform(size=50)
frames =[]
for idx in frame_indices:
cap.set(cv2.CAP_PROP_POS_FRAMES,idx)
ret,frame =cap.read()
frames.append(frame)
median_frame = np.median(frames, axis=0).astype(np.uint8)
return median_frame
#median_frame =get_background("video_1.mp4")
#cv2.imshow("Median_Background",median_frame)
#cv2.waitKey(0)
#cv2.destroyAllWindows()
#plt.show()
code runs fine, but output video does not contain anything, it just 1 KGB size, one thing what i am thinking is that this fragment
frame_diff_list.append(dilate_frame)
is colored with yellow color, here is screenshot :
and also when i try to print print(frame_diff_list)
it just printed one output :
i was more surprised when i have tested
print(ret)
print(frame.shape)
from the begining of the loop and it just printed one output :
True
(360, 640, 3)
it seems that loop does not cover all frames right? could you help me please to figure out what is wrong with my code?

Set background color outside ROI in OpenCV

I successfully displayed the video feed and am trying to change the background color of the area outside ROI from black to blue but the screen still shows black background. Please help me solve the problem. Any help would be greatly appreciated.
Original code
import numpy as np
from cv2 import cv2
'''
ML object detection algo(haarcascade)used to identify objects.
the XML file consists of trained Haar Cascade models.
'''
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
#initialize video from the webcam
video = cv2.VideoCapture(1)
while True:
# ret tells if the camera works properly. Frame is an actual frame from the video feed
ret, frame= video.read()
# print(cv2.VideoCapture(0).isOpened())
# make sure port is working and read the image
if frame is not None and video.isOpened():
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Detect the faces within the subregions of the image in scales
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=6)
# Draw the rectangle around each face
for (x, y, w, h) in faces:
#Use the coordinates to find the center of the face and from that point draw a rectangle of radius w/2 or h/2.
center_coordinates = x + w // 2, y + h // 2
radius = w // 2 # or can be h / 2 or can be anything based on your requirements
#background color(black)
mask=np.zeros(frame.shape[:2] , dtype="uint8")
# Draw the desired region to crop out in white
cv2.circle(mask, center_coordinates, radius, (255,255,255),-1)
masked=cv2.bitwise_and(frame,frame,mask=mask)
cv2.imshow('mask applied',masked)
if cv2.waitKey(30) & 0xff==27:
break
video.release()
cv2.destroyAllWindows()
The above code detects and displays the face in the circular mask on the black background. But as mentioned above, The background color outside circular ROI should be blue.
I tried replacing mask=np.zeros(frame.shape[:2], dtype="uint8")with the code below and fails. Frame.shape[0:2]doesn't even include channel and I can't figure out how to change the color in the first place.
mask=np.ones(frame.shape[0:2], dtype="uint8")
mask[:,:,0]=255
mask[:,:,1]=0
mask[:,:,2]=0
I also tried creating a circular masked image then place it on another image only to find out it results in the same problem.
import numpy as np
from cv2 import cv2
'''
ML object detection algo(haarcascade)used to identify objects.
the XML file consists of trained Haar Cascade models.
'''
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
#initialize video from the webcam
video = cv2.VideoCapture(1)
print(cv2.VideoCapture(1).isOpened())
while True:
# ret tells if the camera works properly. Frame is an actual frame from the video feed
ret, frame= video.read()
# print(cv2.VideoCapture(0).isOpened())
# make sure port is working and read the image
if frame is not None and video.isOpened():
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Detect the faces within the subregions of the image in scales
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=6)
# Draw the rectangle around each face
for (x, y, w, h) in faces:
#Use the coordinates to find the center of the face and from that point draw a rectangle of radius w/2 or h/2.
center_coordinates = x + w // 2, y + h // 2
radius = w // 2 # or can be h / 2 or can be anything based on your requirements
#background color(black)
mask=np.zeros(frame.shape[:2] , dtype="uint8")
# create blue colored background
color = np.full_like(frame, (255,0,0))
# Draw the desired region to crop out in white
roi=cv2.circle(mask, center_coordinates, radius, (255,255,255),-1)
masked=cv2.bitwise_and(frame,frame,mask=mask)
mask_blue=cv2.bitwise_and(color,color,mask=mask-roi)
# combine the two masked images
result = cv2.add(masked,mask_blue)
cv2.imshow('result',result)
if cv2.waitKey(30) & 0xff==27:
break
video.release()
cv2.destroyAllWindows()
I have changed your code as follows according to your requirement. Here i have added an extra line
masked[np.where((masked==[0,0,0]).all(axis=2))]=[255,0,0]
where you can change pixel values of black region to any specific color.
import numpy as np
import cv2
'''
ML object detection algo(haarcascade)used to identify objects.
the XML file consists of trained Haar Cascade models.
'''
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades +'haarcascade_frontalface_default.xml')
#initialize video from the webcam
video = cv2.VideoCapture(0)
print(cv2.VideoCapture(0).isOpened())
while True:
# ret tells if the camera works properly. Frame is an actual frame from the video feed
ret, frame= video.read()
# print(cv2.VideoCapture(0).isOpened())
# make sure port is working and read the image
if frame is not None and video.isOpened():
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Detect the faces within the subregions of the image in scales
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=6)
# Draw the rectangle around each face
for (x, y, w, h) in faces:
#Use the coordinates to find the center of the face and from that point draw a rectangle of radius w/2 or h/2.
center_coordinates = x + w // 2, y + h // 2
radius = w // 2 # or can be h / 2 or can be anything based on your requirements
#background color(black)
mask=np.zeros(frame.shape[:2] , dtype="uint8")
# Draw the desired region to crop out in white
roi=cv2.circle(mask, center_coordinates, radius, (255,255,255),-1)
masked=cv2.bitwise_and(frame,frame,mask=mask)
masked[np.where((masked==[0,0,0]).all(axis=2))]=[255,0,0]
cv2.imshow('result',masked)
if cv2.waitKey(30) & 0xff==27:
break
video.release()
cv2.destroyAllWindows()

How to convert a range of colours to transparent?

I have an image that has different shades of black at the edges and a bit of red in the centre. I want to convert all the black pixels to transparent using opencv. I'm new to opencv so I'd appreciate your help.
I tried following what fireant said in the link: overlay a smaller image on a larger image python OpenCv, but it didn't work. Here's the code I have so far:
img = cv2.imread("/home/uwatt/Downloads/lensf1.jpg")
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
tmp = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
_,alpha = cv2.threshold(tmp,5,255,cv2.THRESH_BINARY)
b,g,r = cv2.split(img)
rgba = [b,g,r,alpha]
dst = cv2.merge(rgba, 4)
plt.imshow(dst)
print(dst.shape)
face_cascade = cv2.CascadeClassifier('/home/uwatt/DIP/lensflare/haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('/home/uwatt/DIP/lensflare/haarcascade_eye.xml')
user = cv2.imread("/home/uwatt/Downloads/Dicaprio.jpg")
gray_user = cv2.cvtColor(user, cv2.COLOR_BGR2GRAY)
user = cv2.cvtColor(user, cv2.COLOR_BGR2BGRA)
faces = face_cascade.detectMultiScale(gray_user, 1.3, 5)
print("Faces:",faces)
for (x,y,w,h) in faces:
roi_gray = gray_user[y:y+h,x:x+w]
roi_color = user[y:y+h,x:x+w]
eyes = eye_cascade.detectMultiScale(roi_gray)
for (ex,ey,ew,eh) in eyes:
print(ex,ey,ew,eh)
#cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,0,255),5)
# resizing & paste the lf image on user
roi_eye = user[y+ey:y+ey+eh,x+ex:x+ex+ew]
resized_lensflare = cv2.resize(dst,(eh,ew))
resized_lensflare = cv2.cvtColor(resized_lensflare, cv2.COLOR_BGR2RGBA)
user[y+ey:y+ey+eh,x+ex:x+ex+ew] = resized_lensflare
You need to use alpha blending to combine the lens flare with the background image. Check out this tutorial to find out more about alpha blending. Here is the stript that I used:
import cv2
flare = cv2.imread("/home/stephen/Desktop/flare.jpg")
user = cv2.imread("/home/stephen/Desktop/leo.jpg")
eyes = [[100,50,200,200],[175,50,200,200]]
for x,y,w,h in eyes:
# resizing & paste the lf image on user
roi_eye = user[y:y+h,x:x+w]
resized_lensflare = cv2.resize(flare,(w,h))
# Make foreground background and alpha
foreground = resized_lensflare.copy()
background = roi_eye.copy()
alpha= foreground.copy()
# Convert uint8 to float
foreground = foreground.astype(float)
background = background.astype(float)
# Normalize the alpha mask to keep intensity between 0 and 1
alpha = alpha.astype(float)/255
# Multiply the foreground with the alpha matte
foreground = cv2.multiply(alpha, foreground)
# Multiply the background with ( 1 - alpha )
background = cv2.multiply(1.0 - alpha, background)
# Add the masked foreground and background.
outImage = cv2.add(foreground, background)
# Mask the user image
user[y:y+h,x:x+w] = outImage
cv2.imshow('img', user)
cv2.waitKey()
cv2.destroyAllWindows()

How to change color to specific portion of an image in opencv python?

I have an image of front facing man in which:
1) I used facial landmark detection to detect the chin point.
2) Add some specific value to lower its y-coordinate value.
3) Find out the width of image.
4) Draw an line through the point.
Now, what I want to do is change the color to portion of image below the yellow line to white color, so that I could have a whole separated head only. How to do that?
Code I have done till now:
import cv2
import numpy as np
import dlib
img1 = cv2.imread('Test.jpg')
#Facial Landmark Detection
predictor_path = "C:\\Users\\G7K4\\Desktop\\BackEnd_New\\01 HeadSwap\\shape_predictor_68_face_landmarks.dat"
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(predictor_path)
img2 = detector(img1)
for k, d in enumerate(img2):
shape = predictor(img1, d)
vec = np.empty([68, 2], dtype = int)
for b in range(68):
vec[b][0] = shape.part(b).x
vec[b][1] = shape.part(b).y
SampleHead_chinPoint = (vec[8,0], vec[8,1])
print(SampleHead_chinPoint )
a = SampleHead_chinPoint[0]
b = SampleHead_chinPoint[1]
c = b + 25
cv2.circle(img1, (a, c), 5, (0,0,255), -1)
cv2.imshow("Pointed", img1)
cv2.waitKey(0)
width = img1.shape[1]
cv2.line(img1, (0,c), (width, c), (0, 255, 255), 2)
cv2.imshow("Lined", img1)
cv2.waitKey(0)
cv2.destroyAllWindows()
Images:
Original Image:
Output 1:
Output 2:
Assumpt you have the chin point.
import cv2
img = cv2.imread("2.png")
chin_point = (370,230)
img[chin_point[0]:,:] = [255,255,255]
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

OpenCV (Python) Drawing on Videos, Tracking

# libraries that will be needed
import numpy as np # numpy
import cv2 # opencv
import imutils # allows video editing
import random
from imutils.object_detection import non_max_suppression
from imutils import paths
import imutils
import cv2
#default HOG
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
# function to trak people
def tracker(cap):
while True:
ret, img = cap.read()
# if video stopped playing, quit
if ret == False:
break
# resize window
img = imutils.resize(img, width = 400)
# convert to graysclae and equalize
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)
# detect people
rects, weights = hog.detectMultiScale(gray, winStride = (8, 8), padding = (8, 8), scale = 1.25)
# store detected people in array
rects = np.array([[x, y, x+w, y+h] for(x, y, w, h) in rects] )
# find largest possible rectangel to avoid detection
# of same person several times
biggest = non_max_suppression(rects, probs = None, overlapThresh = 0.65)
# draw largest rectangle
for (xA, yA, xB, yB) in biggest:
# create random color
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
cv2.rectangle(img, (xA, yA), (xB, yB), color, 2)
# show image
cv2.imshow('Image', img)
k = cv2.waitKey(30) & 0xFF
if k == 27:
break
# run video
cap = cv2.VideoCapture('NYC.mp4')
tracker(cap)
# release frame and destroy windows
cap.release()
cv2.destroyAllWindows
I am attempting to track multiple people at once using OpenCV. Once a person is detected, I draw a rectangle around them. I am having trouble having a random/different color box for each person while maintaining the same color box for a person after they have been detected.
Currently, a person is detected and a box is drawn. In the next frame, if they are still detected a new colored box is drawn, but I would like to maintain the original color.
Also open to tips/tricks that will improve my code and tracking since I am very new to this.
You need a way to say with good confidence this is the person in the next frame if you want to draw same color box for the same person. There are many ways to do it.
One way is you can use tracking. Try using Camshift/meanshift tracking(ofcourse there are many tracking algo, I wont be sure which one suits you best since i dont know your dataset).
Once a person is detected, initialise a tracker and assign a color box to that person. If person is out of the image, then have a system to remove the person from the list.
Hope this helps :)
Your if ret == False: is not indented correctly to match the while True: loop. Current Code:
def tracker(cap):
while True:
ret, img = cap.read()
# if video stopped playing, quit
if ret == False:
break
# resize window
img = imutils.resize(img, width = 400)
# convert to graysclae and equalize
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)
Fixed indentation:
def tracker(cap):
while True:
ret, img = cap.read()
# if video stopped playing, quit
if ret == False:
break
# resize window
img = imutils.resize(img, width = 400)
# convert to graysclae and equalize
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)

Categories

Resources