OpenCV error with AdaptiveThreshold - python

I am trying to capture the video through openCV and then applying Adaptive thresholding on the video (to convert to black and white). The problem is this code throws up error very frequently. I am playing around with the last two numbers in the adaptive threshold function.
cv2.error: /tmp/opencv-UA2sOU/opencv-2.4.9/modules/imgproc/src/thresh.cpp:797: error: (-215) blockSize % 2 == 1 && blockSize > 1 in function adaptiveThreshold
I can't seem to understand what causes this issue.
import numpy as np
import cv2
import pylab as pl
cap = cv2.VideoCapture(0)
# take first frame of the video
ret,frame = cap.read()
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
thresh = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,40,15)
cv2.imshow('frame',thresh)
if cv2.waitKey(1) & 0xFF == ord('q'):
#cv2.imwrite("snap.jpg", thresh)
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

cv2.adaptiveThreshold requires an odd blockSize. So you'd need to use 39 or 41 instead of 40.
blockSize – Size of a pixel neighborhood that is used to calculate a threshold value for the pixel: 3, 5, 7, and so on.
This is indicated by the error message: It says "blockSize % 2 == 1", which means blockSize is not divisible by 2.

Related

img data type = 17 is not supported

Ive got a video which ive im trying to show a specific region using cv2.polyfill and bitwise operation. When I do this on a image it works fine but when done on a video it comes up with the following error. Ive had no problems doing this earlier on with another picture/video. The region to be shown does show up as a frozen picture but also crashes the kernel. The code is:
import cv2
import numpy as np
cap = cv2.VideoCapture("heartvideo.wmv",0)
def roi(frame):
mask = np.zeros_like (frame)
array = np.array([[148,550],[300,650],[400,680],[800,680],[880,560],[555,70],[492,50]])
contours = np.array([[50,50], [50,150], [150,150], [150,50]])
cv2.fillPoly(mask, pts = [array], color =(255))
masked = cv2.bitwise_and(mask,frame)
return mask
while(cap.isOpened()): # while video is initialised
ret, frame = cap.read() #reads the video bit by bit
adj = roi(frame)
if ret:
cv2.imshow("Image", adj)
else:
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
if cv2.waitKey(15) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
error: OpenCV(4.5.3) :-1: error: (-5:Bad argument) in function 'fillPoly'
Overload resolution failed:
img data type = 17 is not supported
Expected Ptr<cv::UMat> for argument 'img'
The issue is that you're using a 3-channel BGR mask (datatype 17 is a 3-channel image). You used np.zeros_like(frame) to set your mask which means that it'll have the exact same dimensions as the image you passed in. If you meant for it to be a 1-channel image you should set the dimensions.
I'm not sure what version of OpenCV you're using and I can't replicate the error with OpenCV 4.4. On this version it allows a 3-channel image even if you've specified a 1-channel color as the fillPoly argument though it does this by assuming you meant (255,0,0) for the color. It could be that on a different version of OpenCV the color dimensions had to match the image dimensions and it's complaining about that.
Try out this revised version of the code and see if it works.
import cv2
import numpy as np
def roi(frame):
# draw a polygon on mask
height,width = frame.shape[:2];
mask = np.zeros((height, width), np.uint8);
array = np.array([[148,550],[300,650],[400,680],[800,680],[880,560],[555,70],[492,50]])
contours = np.array([[50,50], [50,150], [150,150], [150,50]])
cv2.fillPoly(mask, pts = [array], color =(255))
# mask stuff on frame
# masked = cv2.bitwise_and(mask,frame)
copy = np.zeros_like(frame);
copy[mask == 255] = frame[mask == 255];
return copy;
# open video
cap = cv2.VideoCapture("heartvideo.wmv", 0);
while(cap.isOpened()): # while video is initialised
ret, frame = cap.read() #reads the video bit by bit
if ret:
adj = roi(frame)
cv2.imshow("Image", adj)
else:
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
if cv2.waitKey(15) == ord('q'):
break
cap.release()
cv2.destroyAllWindows()

Sobel edge detector on video - not detected in the output file

I am applying sobel edge detector in a video using OpenCV. I can see the result in a window and then I am writing the video. Even though I can see the right result on the window, the result in the output file is not the same.
Here is the code and what I can see in the window and in the output file. Any idea what can cause this?
if between (cap,0,25000): #Apply results on specific milliseconds of the video
Sobel operator - I still need to add colors
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
frame = cv2.Sobel(frame,cv2.CV_64F,1,0,5)
out.write(frame)
frame = cv2.resize(frame, None, fx = 0.2, fy = 0.2, interpolation = cv2.INTER_CUBIC)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
print ("done")
The question has been answered.
I am adding the answer again here:
Sobel output is float per your cv2.CV_64F. That won't be visible since it is in the range of 0 to 1 but your written video frame wants it to be 0 to 255. So you need to scale your results by multiplying by 255 and then clip to range 0 to 255 and save as uint8. frame = (255*cv2.Sobel(frame,cv2.CV_64F,1,0,5) ).clip(0,255).astype(np.uint8). Be sure to import numpy as np

Controlling Contrast and Brightness of Video Stream in OpenCV and Python

I’m using OpenCV3 and Python 3.7 to capture a live video stream from my webcam and I want to control the brightness and contrast. I cannot control the camera settings using OpenCV's cap.set(cv2.CAP_PROP_BRIGHTNESS, float) and cap.set(cv2.CAP_PROP_BRIGHTNESS, int) commands so I want to apply the contrast and brightness after each frame is read. The Numpy array of each captured image is (480, 640, 3). The following code properly displays the video stream without any attempt to change the brightness or contrast.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
I get a washed-out video stream when I use Numpy’s clip() method to control the contrast and brightness, even when I set contrast = 1.0 (no change to contrast) and brightness = 0 (no change to brightness). Here is my attempt to control contrast and brightness.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
contrast = 1.0
brightness = 0
frame = np.clip(contrast * frame + brightness, 0, 255)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
How can I control the contrast and brightness of a video stream using OpenCV?
I found the solution using the numpy.clip() method and #fmw42 provided a solution using the cv2.normalize() method. I like the cv2.normalize() solution slightly better because it normalizes the pixel values to 0-255 rather than clip them at 0 or 255. Both solutions are provided here.
The cv2.normalize() solution:
Brightness - shift the alpha and beta values the same amount. Alpha
can be negative and beta can be higher than 255. (If alpha >= 255,
then the picture is white and if beta <= 0, then the picure is black.
Contrast - Widen or shorten the gap between alpha and beta.
Here is the code:
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
cv2.normalize(frame, frame, 0, 255, cv2.NORM_MINMAX)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
The numpy.clip() solution:
This helped me solve the problem: How to fast change image brightness with python + OpenCV?. I need to:
Convert Red-Green Blue (RGB) to Hue-Saturation-Value (HSV) first
(“Value” is the same as “Brightness”)
“Slice” the Numpy array to the Value portion of the Numpy array and adjust brightness and contrast on that slice
Convert back from HSV to RGB.
Here is the working solution. Vary the contrast and brightness values. numpy.clip() ensures that all the pixel values remain between 0 and 255 in each on the channels (R, G, and B).
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
contrast = 1.25
brightness = 50
frame[:,:,2] = np.clip(contrast * frame[:,:,2] + brightness, 0, 255)
frame = cv2.cvtColor(frame, cv2.COLOR_HSV2BGR)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
import cv2 as cv
cap = cv.VideoCapture(0)
while True:
# Capture frame-by-frame
ret, frame = cap.read()
# normalize the frame
frame = cv.normalize(
frame, None, alpha=0, beta=255, norm_type=cv.NORM_MINMAX, dtype=cv.CV_8UC1
)
# Display the resulting frame
cv.imshow("frame", frame)
# press q to quit
if cv.waitKey(1) & 0xFF == ord("q"):
break

get frame from video with CV_CAP_PROP_POS_FRAMES in opencv python

I am trying to detect a (photography) flash in a video using OpenCV.
I detected the frame in which the flash occurs (average brightness above a threshold) and now I'd like to get the frame number.
I tried using CV_CAP_PROP_POS_FRAMES from the OpenCV docs without any success.
import numpy as np
import cv2
cap = cv2.VideoCapture('file.MOV')
while(cap.isOpened()):
ret, frame = cap.read()
BW = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
h,s,v = cv2.split(hsv)
average = np.average(v) #computes the average brightness
if average > 200: #flash is detected
cv2.imshow('frame',BW)
frameid = cap.get(CV_CAP_PROP_POS_FRAMES) # <--- this line does not work
print(frameid)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Any tips ?
You can either:
Use cap.get(cv2.CAP_PROP_POS_FRAMES) (see here, also), or
increment a variable at each iteration: its current value is the current frame number
From opencv-doc:
When querying a property that is not supported by the backend used by the VideoCapture class, value 0 is returned
Probably it is not supported. In that case you have to count the frame number yourself.

In OpenCV I've got a mask of an area of a frame. How would I then insert another image into that location on the original frame?

I'm brand new to OpenCV and I can't seem to find a way to do this (It probably has to do with me not knowing any of the specific lingo).
I'm looping through the frames of a video and pulling out a mask from the video where it is green-screened using inRange. I'm looking for a way to then insert an image into that location on the original frame. The code i'm using to pull the frames/mask is below.
import numpy as np
import cv2
cap = cv2.VideoCapture('vid.mov')
image = cv2.imread('photo.jpg')
# green digitally added not much variance
lower = np.array([0, 250, 0])
upper = np.array([10, 260, 10])
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
cv2.imshow('frame', frame)
# get mask of green area
mask = cv2.inRange(frame, lower, upper)
cv2.imshow('mask', mask)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
Use Bitwise operations for masking and related binary operations. Please check below code to see how Bitwise operations are done.
Code
import numpy as np
import cv2
cap = cv2.VideoCapture('../video.mp4')
image = cv2.imread('photo.jpg')
# green digitally added not much variance
lower = np.array([0, 250, 0])
upper = np.array([10, 260, 10])
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
cv2.imshow('frame', frame)
# get mask of green area
mask = cv2.inRange(frame, lower, upper)
notMask = cv2.bitwise_not(mask)
imagePart=cv2.bitwise_and(image, image, mask = mask)
videoPart=cv2.bitwise_and(frame, frame, mask = notMask)
output = cv2.bitwise_or(imagePart, videoPart)
cv2.imshow('output', output)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
RGB bad color space
Since, you are doing color processing, I would suggest you to use appropriate color space. HSV would be a good start for you. For finding good range of HSV values, try this script.
Generating Video Output
You need a to create a video writer and once all image processing is done, write the processed frame to a new video. I am pretty sure, you cannot read and write to same video file.
Further see official docs here.
It has both examples of how to read and write video.

Categories

Resources