create a mask and delete inside contour in opencv python - python

this is the result that I have from my code :
enter image description here
I've made this mask on my face using contour , as I show bellow in the code .
the final result of the project is to delete the face and show the background that I am not defined it yet .
my question is : is there any way to make a mask with this counter so i could use something like this cv2.imshow('My Image',cmb(foreground,background,mask)) to just show the foreground under the mask on the background ? ( the problem here is that i must have the mask as a video in this form but i want it to be real time)
or perhaps the other way , could i somehow delete the pixels of frame in (or under) my counter ?
this is my code :
from imutils.video import VideoStream
from imutils import face_utils
import datetime
import argparse
import imutils
import time
import dlib
import cv2
import numpy as np
# path to facial landmark predictor
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--shape-predictor", required=True)
print("[INFO] loading facial landmark predictor...")
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor(args["shape_predictor"])
# grab the indexes of the facial landmarks
(lebStart, lebEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eyebrow"]
(rebStart, rebEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eyebrow"]
(jawStart, jawEnd) = face_utils.FACIAL_LANDMARKS_IDXS["jaw"]
# initialize the video stream and allow the cammera sensor to warmup
print("[INFO] camera sensor warming up...")
vs = VideoStream(usePiCamera=args["picamera"] > 0).start()
time.sleep(2.0)
# loop over the frames from the video stream
while True:
# grab the frame from the threaded video stream, resize it to
# have a maximum width of 400 pixels, and convert it to
# grayscale
frame = vs.read()
frame = imutils.resize(frame, width=400)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# detect faces in the grayscale frame
rects = detector(gray, 0)
# loop over the face detections
for rect in rects:
shape = predictor(gray, rect)
shape = face_utils.shape_to_np(shape)
# extract the face coordinates, then use the
faceline = shape[jawStart:lebEnd]
# compute the convex hull for face, then
# visualize each of the face
facelineHull = cv2.convexHull(faceline)
mask = np.zeros(frame.shape,dtype='uint8')
cv2.drawContours(frame, [facelineHull], -1, (0, 0, 0),thickness=cv2.FILLED)
cv2.drawContours(frame, [facelineHull], -1, (0, 255, 0))
# show the frame
cv2.imshow("Frame", frame)
# cv2.imshow("Frame", mask)
key = cv2.waitKey(1) & 0xFF
# if the `q` key was pressed, break from the loop
if key == ord("q"):
break
# do a bit of cleanup
cv2.destroyAllWindows()
vs.stop()

here is my solution for deleting face from frame( it is faster but again thanks to #meetaig for help)
mask = np.zeros(frame.shape,dtype='uint8')
mask = cv2.drawContours(mask, [facelineHull], -1, (255 , 255 , 255),thickness=cv2.FILLED)
mask = cv2.bitwise_not(mask)
img2gray = cv2.cvtColor(mask,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
result= cv2.bitwise_and(frame,frame,mask=mask)
and if i show result now it will work.
cv2.imshow("Frame", result)

Assuming your mask is a binary mask you could do the following:
def cmb(foreground,background,mask):
result = background.copy()
result[mask] = foreground[mask]
return result
I did not test this code, but I hope the idea comes across. You invert the mask for the background and leave the mask alone for the foreground. You apply this to every frame and voilà, you have your masked images.
edit:
adjusted code according to comment. Of course that solution is much clearer than what I originally wrote. The functionality stays the same, though.

Related

Segment black AND moving Pixels

I’m trying to segment the moving propeller of this Video. My approach is, to detect all black and moving pixels to separate the propeller from the rest.
Here is what I tried so far:
import numpy as np
import cv2
x,y,h,w = 350,100,420,500 # Croping values
cap = cv2.VideoCapture('Video Path')
while(1):
_, frame = cap.read()
frame = frame[y:y+h, x:x+w] # Crop Video
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_black = np.array([0,0,0])
upper_black = np.array([360,255,90])
mask = cv2.inRange(hsv, lower_black, upper_black)
res = cv2.bitwise_and(frame,frame, mask= mask)
nz = np.argwhere(mask)
cv2.imshow('Original',frame)
cv2.imshow('Propeller Segmentation',mask)
k = cv2.waitKey(30) & 0xff # press esc to exit
if k == 27:
break
cap.release()
cv2.destroyAllWindows()
Screenshot form the Video
Result of the Segmentation
With function cv.createBackgroundSubtractorMOG2()
I think you should have a look at background subtraction. It should be the right approach for your problem.
OpenCV provides a good tutorial on this: Link

Decode barcodes & Qr codes using deep learning

Objective:
I have a drone and it has to detect and decode all barcodes and QR-codes(small or big) from 3 meters distance. Even though I have been able to achieve the same on a hand-held camera, the same does not work on a drone, as it's very hard to keep the drone constant without moving.
Research Done:
I surfed the internet and found a program by pyimagesearch, where it draws bounding boxes on the detected barcode. The program consists of two files namely,
1.simple_barcode_detection.py: Processes the received frame and return the bounding box locations of the barcode.
2.detect_barcode.py: Sends the input frames to simple_barcode_detection.py and displays the returned frames. note:(This program successfully drew bounding boxes on the barcode).
I am attaching the current status of the code which I have built from this.
simple_barcode_detection.py:
# import the necessary packages
import numpy as np
import cv2
import imutils
from pyzbar import pyzbar
import imutils
global text, box
def detect(image):
# convert the image to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# compute the Scharr gradient magnitude representation of the images
# in both the x and y direction using OpenCV 2.4
ddepth = cv2.cv.CV_32F if imutils.is_cv2() else cv2.CV_32F
gradX = cv2.Sobel(gray, ddepth=ddepth, dx=1, dy=0, ksize=-1)
gradY = cv2.Sobel(gray, ddepth=ddepth, dx=0, dy=1, ksize=-1)
# subtract the y-gradient from the x-gradient
gradient = cv2.subtract(gradX, gradY)
gradient = cv2.convertScaleAbs(gradient)
# blur and threshold the image
blurred = cv2.blur(gradient, (9, 9))
(_, thresh) = cv2.threshold(blurred, 225, 255, cv2.THRESH_BINARY)
# construct a closing kernel and apply it to the thresholded image
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 7))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# perform a series of erosions and dilations
closed = cv2.erode(closed, None, iterations=4)
closed = cv2.dilate(closed, None, iterations=4)
# find the contours in the thresholded image
cnts = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
# if no contours were found, return None
if len(cnts) == 0:
return None
# otherwise, sort the contours by area and compute the rotated
# bounding box of the largest contour
c = sorted(cnts, key=cv2.contourArea, reverse=True)[0]
rect = cv2.minAreaRect(c)
box = cv2.cv.BoxPoints(rect) if imutils.is_cv2() else cv2.boxPoints(rect)
box = np.int0(box)
return box
# draw a bounding box arounded the detected barcode and display the frame
def process(image,box):
min_y = int(np.min(box[:,-1]))
max_y = int(np.max(box[:,-1]))
min_x = int(np.min(box[:,0]))
max_x = int(np.max(box[:,0]))
image = image[min_y:max_y, min_x:max_x]
barcodes = pyzbar.decode(image)
# Processing the barcode #
for barcode in barcodes:
(x, y, w, h) = barcode.rect
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)
barcodeData = barcode.data.decode("utf-8")
barcodeType = barcode.type
text = "{} ({})".format(barcodeData, barcodeType)
return text
detect_barcode.py
# import the necessary packages
import simple_barcode_detection
from imutils.video import VideoStream
import argparse
import time
import cv2
from pyzbar import pyzbar
import imutils
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video",
help="path to the (optional) video file")
args = vars(ap.parse_args())
# if the video path was not supplied, grab the reference to the
# camera
if not args.get("video", False):
vs = VideoStream(src=0).start()
time.sleep(2.0)
# otherwise, load the video
else:
vs = cv2.VideoCapture(args["video"])
# keep looping over the frames
while True:
frame = vs.read()
frame = frame[1] if args.get("video", False) else frame
if frame is None:
break
box = simple_barcode_detection.detect(frame)
if box is not None:
cv2.putText(frame, text, (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
cv2.imshow("Frame", frame)
# cv2.imshow("Frame", image)
key = cv2.waitKey(1) & 0xFF
# if the 'q' key is pressed, stop the loop
if key == ord("q"):
break
# if we are not using a video file, stop the video file stream
if not args.get("video", False):
vs.stop()
# otherwise, release the camera pointer
else:
vs.release()
# close all windows
cv2.destroyAllWindows()
Error:
line 30, in <module> cv2.putText(frame, text, (x, y - 10), NameError: name 'text' is not defined
Adding to the same I also found a research paper, where yolo and pyzbar are used to identify and decode the barcode.
Question:
Is there any possibility that we can accept the returned bounding box locations and send them to pyzbar so that it scans that region for barcodes?
How does pyzbar work & can we create a similar library like pyzbar?
Reference images:
Drone not able to scan barcode
Drone not able to scan barcodes of this size
Links:
https://www.pyimagesearch.com/2014/12/15/real-time-barcode-detection-video-python-opencv/
https://d1wqtxts1xzle7.cloudfront.net/63796937/rahman-2019-ijais-451835_IJAIS20200701-113597-137d8us-with-cover-page-v2.pdf?Expires=1637915838&Signature=geCHJHKsaMnDCJMzNAz-OHHjxXSdX~rLtTf-MO0gGuNutOnHl5x33q8-Xiab4haQGnhuE8ektKO4Ah2REj9nebwfwnO3GYxBGRqZgqMsK63375AUQV7YsTjJz9Qwp~OwUa9st2h4a6~ep3eSwvCjCX-Dl-g612osElU6ATgdI4DGqqaaat-QuLAmjQqywXTZrTWs0~nLvVeZBLEJRnNbcphtlJPv1yM35Ix2AhiwKhax4X4qCqLR7Wzt3XR5IaW33X3zSPNoo0QhDLEZrEFG0m-Hi156fsq488mC4n6Udyoi8KNhaUxqQ316b7Zru7XF1z1UaBbGU44O4nuI5AtflA__&Key-Pair-Id=APKAJLOHF5GGSLRBV4ZA

Python video analysis -- detecting color change and time stamp

I'm trying to use OpenCV to analyze a 10 min video for green in the top right corner and printing out the time stamps every time there is green.
I've used meanshift and tried splitting it into frames but a 10 minute long video would require a lot of frames -- especially since I'm trying to be accurate.
I was thinking of masking over the green, but there isn't a way to print the time stamps... any tips on what packages or tools I should use?
Here's what I have, and I've tried basically everything in OpenCV but I've never used it before so I'm lost...
import cv2
import numpy as np
cap = cv2.VideoCapture('video.mp4')
# This drives the program into an infinite loop.
while(1):
# Captures the live stream frame-by-frame
_, frame = cap.read()
# Converts images from BGR to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
lower_red = np.array([121, 240, 9]) # darker green
upper_red = np.array([254,255,255]) # white green
# Defining range of green color in HSV
# This creates a mask
mask = cv2.inRange(hsv, lower_red, upper_red)
# that only the green coloured objects are highlighted
res = cv2.bitwise_and(frame,frame, mask= mask)
cv2.imshow('frame',frame)
cv2.imshow('mask',mask)
cv2.imshow('res',res)
k = cv2.waitKey(5) & 0xFF
# if k == 27: break
# Destroys all of the HighGUI windows.
cv2.destroyAllWindows()
# release the captured frame
cap.release()
Splitting the frames gives me thousands of images and just reading the video doesn't give me time stamps, which is what I want it to print out. Thanks!

OpenCv - create mask from edge - crop and save image

I have a video with opaque logo, my goal is to identify area of image that remain still and extract it.
this is my code:
import cv2
import numpy as np
import imutils
c = cv2.VideoCapture('sky.mp4')
_,f = c.read()
avg2 = np.float32(f)
while(1):
_,f = c.read()
cv2.accumulateWeighted(f,avg2,0.005)
#cv2.accumulateWeighted(f,avg2,0.01)
res2 = cv2.convertScaleAbs(avg2)
# load the query image, compute the ratio of the old height
# to the new height, clone it, and resize it
ratio = res2.shape[0] / 300.0
orig = res2.copy()
res2 = imutils.resize(res2, height = 600)
# convert the image to grayscale, blur it, and find edges
# in the image
gray = cv2.cvtColor(res2, cv2.COLOR_BGR2GRAY)
gray = cv2.bilateralFilter(gray, 11, 17, 17)
edged = cv2.Canny(gray, 30, 200)
cv2.imshow('img',f)
cv2.imshow('avg2',edged)
k = cv2.waitKey(20)
if k == 27:
break
cv2.destroyAllWindows()
c.release()
The cv2.accumulateWeighted funtion, after time pass, permits to clearly identify parts that remain mostly still on the frames.
orig frame part:
edged averaged frame part:
How can I create a mask for the entire averaged edged part, crop it and save it in a separate image?
You can use cv2.findContours() to do connected component analysis. Then use cv2.boundingRect() to get the bounding box. Then you can crop the image using img[r1:r2, c1:c2] using Numpy slicing.

Drone Feedback: Object Detection / Color Detection? Is there way just to isolate detection on a specific object

I have been working on a code where an A.R Drone 2.0 will detect color and put a red dot in the middle of the image. I am using streaming for the drone. The goal is for the drone to detect a white gutter and fly straight over it from one point to the other. Essentially following a line. I noticed when I changed the BGR to 0, 0, 255, I get the entire gutter to be distinguished but it detects white spots as well. Is there to isolate my detection just to see the gutter. Maybe using shapes, once the gutter is detected, put a bounding box. And my finally question is how do I tell my drone to follow the red dot or maybe drawing a line. I looked at python-AR drone libraries but don't know how to apply it.This is my code.
import numpy as np
import cv2
# open the camera
cap = cv2.VideoCapture('tcp://192.168.1.1:5555')
def nothing(x):
pass
cv2.namedWindow('result')
# Starting with 100's to prevent error while masking
h,s,v = 100,100,100
# Creating track bar
cv2.createTrackbar('h', 'result',0,179,nothing)
cv2.createTrackbar('s', 'result',0,255,nothing)
cv2.createTrackbar('v', 'result',0,255,nothing)
while True:
#read the image from the camera
ret, frame = cap.read()
#You will need this later
frame = cv2.cvtColor(frame, 35)
#converting to HSV
hsv = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
# get info from track bar and appy to result
h = cv2.getTrackbarPos('h','result')
s = cv2.getTrackbarPos('s','result')
v = cv2.getTrackbarPos('v','result')
# Normal masking algorithm
lower_blue = np.array([h,s,v])
upper_blue = np.array([180,255,255])
mask = cv2.inRange(hsv,lower_blue, upper_blue)
result = cv2.bitwise_and(frame,frame,mask = mask)
cv2.imshow('result',result)
#find center
cnts=cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
center=None
if len(cnts)>0:
c=max(cnts, key=cv2.contourArea)
((x,y),radius)=cv2.minEnclosingCircle(c)
M=cv2.moments(c)
center=(int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))
if radius>10:
#cv2.circle(frame, (int(x),int(y)), int(radius), 2)
cv2.circle(frame, center,5,(0,0,255),-1)
# color detection limits
lB = 5
lG = 50
lR = 50
hB = 15
hG = 255
hR = 255
lowerLimits = np.array([lB, lG, lR])
upperLimits = np.array([hB, hG, hR])
# Our operations on the frame come here
thresholded = cv2.inRange(frame, lowerLimits, upperLimits)
outimage = cv2.bitwise_and(frame, frame, mask = thresholded)
cv2.imshow('original', frame)
# Display the resulting frame
cv2.imshow('processed',outimage)
# Quit the program when Q is pressed
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
print 'closing program'
cap.release()
cv2.destroyAllWindows()

Categories