Replacing 3D submatrix in Numpy and OpenCV2 - python

Replace sub part of matrix by another small matrix in numpy generally seems to work for my purposes but I'm running into something I can't reconcile. Consider the following code, that creates two 3D matrices the shape of OpenCV2 webcam input, (in my case (480, 640, 3)), one of all 1s (frame) and one of random floats (rgb_noise_mask), replaces a specified submatrix in frame with the same submatrix of rgb_noise_mask, and displays it to the screen. This code works as intended, displaying a block of RGB-based static on a field of white.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
frame = np.ones(frame.shape)
rgb_noise_mask = np.random.random(size=frame.shape)
while True:
boxes = [[300,300,30,30]]
for box in boxes:
x, y, width, height = box
frame[y:y2, x:x2] = rgb_noise_mask[y:y2, x:x2]
cv2.imshow("frame", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cap.release()
cv2.destroyAllWindows()
Now take off the training wheels and use the actual webcam input instead of faking it. That same box now appears as uniform black instead of the expected colors:
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
rgb_noise_mask = np.random.random(size=frame.shape)
while True:
ret, frame = cap.read()
boxes = [[300,300,30,30]]
for box in boxes:
x, y, width, height = box
frame[y:y2, x:x2] = rgb_noise_mask[y:y2, x:x2]
cv2.imshow("frame", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cap.release()
cv2.destroyAllWindows()
Why is this, and how can I get around it? Further adding to my confusion is that if I replace frame[y:y2, x:x2] = rgb_noise_mask[y:y2, x:x2] with frame[y:y2, x:x2] = frame[y:y2, x:x2][::-1] in the second code sample it behaves as expected and displays the live output with that square mirrored.

The issue here is that ret, frame = cap.read() returns frame as a numpy array with dtype=np.uint8, while rgb_noise_mask is float between 0,1, so all 0 when converted to uint8.
A simple fix is to generate noise as integers with randint:
rgb_noise_mask = np.random.randint(0,256, size=frame.shape, dtype=np.uint8)

Related

How to get RGB values from a video?

I want to get the RGB values of a video and put it in a 2D array with frames (frame,rgb value) and save it in a file.
I only found a way to get it on image pixles and don't know how to save the array in a file.
from PIL import Image
im = Image.open("D:\swim\Frames1\Frames1.png")
pix=im.load()
width, height = im.size
pixels = [pix[i, j] for i in range(width) for j in range(height)]
print (pixels)
in conclusion: I want to load a video and convert it to an array consisting of frames,RGB is that possible?
I have tried
from numpy import asarray
from numpy import savetxt
import cv2
cap = cv2.VideoCapture('D:\swim\swim99.mp4')
rgb_list = []
while True:
ret, frame = cap.read()
if not ret:
break
rgb_frame_i = frame.reshape(-1, 3).tolist()
rgb_list.extend(rgb_frame_i)
print(rgb_frame_i)
but it didn't print anything and I don't know how to save it in a file.
Things you should know:
Step 1 - Convert your videos into Frames
import numpy as np
import cv2 as cv
cap = cv.VideoCapture(0)
if not cap.isOpened():
print("Cannot open camera")
exit()
while True:
# Capture frame-by-frame
ret, frame = cap.read()
-------------------------------------------------------------> step 2 - split
# if frame is read correctly ret is True
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
# Our operations on the frame come here
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# Display the resulting frame
cv.imshow('frame', gray)
if cv.waitKey(1) == ord('q'):
break
# When everything done, release the capture
cap.release()
cv.destroyAllWindows()
Step 2 - Split your frames into B,G,R
b,g,r = cv2.split(frame)
Step 3 - Save independent frames and convert to a video.

How to insert a smaller image in an opencv Videocapture frame?

So, I have this code, I can easily add a text or any shape in opencv frame.
But inserting an image on a frame is a very difficult one.
I want to insert a smaller image on a Videocapture frame, let say the image to be inserted is a 50x50 pixel.
Any idea on this?
import cv2
webcam = cv2.VideoCapture(0)
insertImage = "sample.jpg" # size 50x50
while True:
rval = False
while(not rval):
(rval, frame) = webcam.read()
if(not rval):
print("Failed to open webcam. Trying again...")
cv2.putText(frame, " image here ", (0,70),cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255,0,0), 2)
cv2.imshow('with image', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
webcam.release()
cv2.destroyAllWindows()
OpenCv images are numpy arrays. As far as I know, OpenCv does not provide functions with which you can get what you want. The result can be achieved by manipulating arrays.
import cv2
import numpy as np
if __name__ == '__main__':
bigImage = cv2.imread("image1.png") #I don't have a webcam connected, so it's your frame
smallImage = cv2.imread("image2.png") #50x50 for you
height, width, channels = smallImage.shape
offset = np.array((40, 50)) #top-left point from which to insert the smallest image. height first, from the top of the window
bigImage[offset[0]:offset[0] + height, offset[1]:offset[1] + width] = smallImage
cv2.imshow("test", bigImage)
cv2.waitKey(0)
Input
bigImage = big gray rectangle. It is your frame
smallImage = small green rectangle. It is your 50x50 image
Output

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

How do I find an image similar to the input image from a directory?

I have a python program which will detect images from webcam. Now, I want to compare the image recognized by the webcam with the images in my directory and check if the exact similar image is already existing or not.
I have tried using this recognition algorithm but it does not work. The program always outputs single image no matter how different the input image is.
The input image(the image scanned by the webcam) is little blurry like this while the image in the data set looks like this
I need an algorithm which can recognize these images with more accuracy.
Here i write a small script for you, hope that it could solve your problem
import cv2
import os
import numpy as np
from matplotlib import pyplot as plt
from PIL import Image
def read_img_from_dir(directory, query_shape):
# query_shape is a tuple which contain the size (width, height) of query image
# directory is your dir contain image you wanna find
name_image = []
shape = query
first = True
for pics in os.listdir(directory):
name_image.append(pics)
image = Image.open(pics)
image = image.resize(shape)
image = np.array(image)
image = np.reshape(image,(1,-1))
if first:
img_array = np.copy(image)
first = False
else:
img_array = np.concatenate((img,array,image),axis=0)
return name_image, img_array
def find_by_knn(img, list_name, list_array):
# image_query is path of your picture you wanna find
# list_name and list_array is result of above function
img = np.reshape(img,(1,-1))
num_pics = list_array.shape[0]
dists = np.zeros((num_pics,1))
dists = list(np.sqrt(np.sum((list_array-img)**2,axis = 1)))
idx = dists.index(max(dists))
return list_name[idx]
img = cv2.imread(image_query)
shape = img.shape[:2]
name_image, img_array = read_img_from_dir(directory,shape)
result = find_by_knn(img, name_image, img_array)
print(result)
If you wanna know more about KNN, take a look at this link: http://cs231n.github.io/classification/#nn
IMAGE SEARCH by using python openCV.
LINK FOR open CV
opencv_python‑4.1.0+contrib‑cp35‑cp35m‑win_amd64.whl
download the import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('watch.jpg',cv2.IMREAD_GRAYSCALE)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
pip install numpy
pip install matplotlib
Matplotlib is used for displaying frames from video or images.
Numpy is used for all things "numbers and Python."
We are mainly making use of Numpy's array functionality.
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('watch.jpg',cv2.IMREAD_GRAYSCALE)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Firstly we are going to import few things
Next, we define img to be cv2.read(image file, parms).
The default is going to be IMREAD_COLOR, which is color without any alpha channel.
For the second parameter, you can use -1, 0, or 1. Color is 1, gray scale is 0, and the unchanged is -1. Thus, for gray scale, one could do img = cv2.imread('watch.jpg', 0)
Once loaded, we use cv2.imshow(title,image) to show the image. From here,
we use the cv2.waitKey(0) to wait until any key is pressed. Once that's done,
we use cv2.destroyAllWindows() to close everything.
Loading Video Source Open CV Python
with video and webcams.
handling frames from a video is identical to handling for images.
code--
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
we import numpy and cv2 Next, we cay cap = cv2.VideoCapture(0).
while(True):
ret, frame = cap.read()
we have ret and frame being defined as the cap.read().
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
*we define a new variable, gray, as the frame, converted to gray.
note**
*OpenCV reads colors as BGR (Blue Green Red),
where most computer applications read as RGB (Red Green Blue).
cv2.imshow('frame',gray)
Here, we're showing the converted-to-gray feed.
if cv2.waitKey(1) & 0xFF == ord('q'):
break
if key is a q, we will exit the while loop with a break, which then runs:
cap.release()
cv2.destroyAllWindows()
This releases the webcam, then closes all of the imshow() windows.
if you want to save the recording and then process it by using,
import numpy as np
import cv2
cap = cv2.VideoCapture(1)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))
while(True):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
out.write(frame)
cv2.imshow('frame',gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()

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