how can I display multiple cameras in one window?(OpenCv)
Using this code: Capturing video from two cameras in OpenCV at once , I open multiple cameras in separate windows, but I want to show them in one.
I found code for concanating images https://answers.opencv.org/question/188025/is-it-possible-to-show-two-video-feed-in-one-window/ but it doesn't work with cameras.
Same question was asked here previously, but no answer was given.
You can do this using numpy methods.
Option 1: np.vstack/np.hstack
Option 2: np.concatenate
Note 1: The methods will fail if you have different frames sizes because you are trying to do operation on matrices of different dimensions. That's why I resized one of the frames to fit the another.
Note 2: OpenCV also has hconcat and vconcat methods but I didn't try to use them in python.
Example Code: (using my Camera feed and a Video)
import cv2
import numpy as np
capCamera = cv2.VideoCapture(0)
capVideo = cv2.VideoCapture("desk.mp4")
while True:
isNextFrameAvail1, frame1 = capCamera.read()
isNextFrameAvail2, frame2 = capVideo.read()
if not isNextFrameAvail1 or not isNextFrameAvail2:
break
frame2Resized = cv2.resize(frame2,(frame1.shape[0],frame1.shape[1]))
# ---- Option 1 ----
#numpy_vertical = np.vstack((frame1, frame2))
numpy_horizontal = np.hstack((frame1, frame2))
# ---- Option 2 ----
#numpy_vertical_concat = np.concatenate((image, grey_3_channel), axis=0)
#numpy_horizontal_concat = np.concatenate((frame1, frame2), axis=1)
cv2.imshow("Result", numpy_horizontal)
cv2.waitKey(1)
Result: (for horizontal concat)
Related
I have a 3d image which is the segmentation result of a input volume, the system works fine except for when two cells are located very close to each other, then in that case the segmentation results come back as the two cells joined as shown in the image below:
The circled are are actually two cells but are joined combined due to being closely located. In CC counting these two come up as a single cell.
I tried using morphological opening but it does not seem to provide the result I want. With a single iteration I have no effect ad with enough iterations to break the gap, I lose the smaller blobs.
import imageio as io
import numpy as np
import skimage.morphology as morph
import scipy.ndimage as ndimage
img = io.volread('test_volumes/volume_4_1_predictions.tif')
bw_img = img > 0.5 # binrize image
bw_img = 1 - bw_img # this changes True False to 1 and 0
bw_img = 1 - bw_img # Make background black and foreground white
strel = morph.ball(1)
opened = ndimage.binary_opening(opened, strel, 5)
5 iterations of this opens the gap but i seem to lose a lot of information.
Erosion does not work either as it loses more information than opening.
What would be the best way to disconnect these two cells?
Here is the 3d image in.tif format: https://app.box.com/s/9wcqf3qbn8d9jg8zfvw3ijz85baes8t4
I use OpenCV and Python and I want to remove the small connected object from my image.
I have the following binary image as input:
The image is the result of this code:
dilation = cv2.dilate(dst,kernel,iterations = 2)
erosion = cv2.erode(dilation,kernel,iterations = 3)
I want to remove the objects highlighted in red:
How can I achieve this using OpenCV?
How about with connectedComponentsWithStats (doc):
# find all of the connected components (white blobs in your image).
# im_with_separated_blobs is an image where each detected blob has a different pixel value ranging from 1 to nb_blobs - 1.
nb_blobs, im_with_separated_blobs, stats, _ = cv2.connectedComponentsWithStats(im)
# stats (and the silenced output centroids) gives some information about the blobs. See the docs for more information.
# here, we're interested only in the size of the blobs, contained in the last column of stats.
sizes = stats[:, -1]
# the following lines result in taking out the background which is also considered a component, which I find for most applications to not be the expected output.
# you may also keep the results as they are by commenting out the following lines. You'll have to update the ranges in the for loop below.
sizes = sizes[1:]
nb_blobs -= 1
# minimum size of particles we want to keep (number of pixels).
# here, it's a fixed value, but you can set it as you want, eg the mean of the sizes or whatever.
min_size = 150
# output image with only the kept components
im_result = np.zeros_like(im_with_separated_blobs)
# for every component in the image, keep it only if it's above min_size
for blob in range(nb_blobs):
if sizes[blob] >= min_size:
# see description of im_with_separated_blobs above
im_result[im_with_separated_blobs == blob + 1] = 255
Output :
In order to remove objects automatically you need to locate them in the image.
From the image you provided I see nothing that distinguishes the 7 highlighted items from others.
You have to tell your computer how to recognize objects you don't want. If they look the same, this is not possible.
If you have multiple images where the objects always look like that you could use template matching techniques.
Also the closing operation doesn't make much sense to me.
#For isolated or unconnected blobs: Try this (you can set noise_removal_threshold to whatever you like and make it relative to the largest contour for example or a nominal value like 100 or 25).
mask = np.zeros_like(img)
for contour in contours:
area = cv2.contourArea(contour)
if area > noise_removal_threshold:
cv2.fillPoly(mask, [contour], 255)
Removing small connected components by area is called area opening. OpenCV does not have this as a function, it can be implemented as shown in other answers. But most other image processing packages will have an area opening function.
For example using scikit-image:
import skimage
import imageio.v3 as iio
img = iio.imread('cQMZm.png')[:,:,0]
out = skimage.morphology.area_opening(img, area_threshold=150, connectivity=2)
For example using DIPlib:
import diplib as dip
out = dip.AreaOpening(img, filterSize=150, connectivity=2)
PS: The DIPlib implementation is noticeably faster. Disclaimer: I'm an author of DIPlib.
How can I extract frames from a video file using Python3?
For example, I want to get 16 picture from a video and combine them into a 4x4 grid.
I don't want 16 separate images at the end, I want one image containing 16 frames from the video.
----Edit----
import av
container = av.open('/home/uguraba/Downloads/equals/equals.mp4')
video = next(s for s in container.streams)
for packet in container.demux(video):
for frame in packet.decode():
if frame.index %3000==0:
frame.to_image().save('/home/uguraba/Downloads/equals/frame-%04d.jpg' % frame.index)
By using this script i can get frames. There will be lots of frames saved. Can i take specific frames like 5000-7500-10000 ?
Also my question is how can i see the total frame number ?
Use PyMedia or PyAV to access image data and PIL or Pillow to manipulate it in desired form(s).
These libraries have plenty of examples, so with basic knowledge about the video muxing/demuxing and picture editing you should be able to do it pretty quickly. It's not so complicated as it would seem at first.
Essentially, you demux the video stream into frames, going frame by frame.
You get the picture either in its original (e.g. JPEG) or raw form and push it into PIL/Pillow.
You do with it what you want, resizing etc... - PIL provides all necessary stuff.
And then you paste it into one big image at desired position.
That's all.
You can do that with OpenCV3, the Python wrapper and Numpy.
First you need to do is capture the frames then save them separately and finally paste them all in a bigger matrix.
import numpy as np
import cv2
cap = cv2.VideoCapture(video_source)
# capture the 4 frames
_, frame1 = cap.read()
_, frame2 = cap.read()
_, frame3 = cap.read()
_, frame4 = cap.read()
# 'glue' the frames using numpy and vertigal/horizontal stacks
big_frame = np.vstack((np.hstack((frame1, frame2)),
np.hstack((frame3, frame4))))
# Show a 4x4 unique frame
cv2.imshow('result', big_frame)
cv2.waitKey(1000)
To compile and install OpenCV3 and Numpy in Python3 you can follow this tutorial.
You can implement a kind of "control panel" from 4 different video sources with something like that:
import numpy as np
import cv2
cam1 = cv2.VideoCapture(video_source1)
cam2 = cv2.VideoCapture(video_source2)
cam3 = cv2.VideoCapture(video_source3)
cam4 = cv2.VideoCapture(video_source4)
while True:
more1, frame_cam1 = cam1.read()
more2, frame_cam2 = cam2.read()
more3, frame_cam3 = cam3.read()
more4, frame_cam4 = cam4.read()
if not all([more1, more2, more3, more4]) or cv2.waitKey(1) & 0xFF in (ord('q'), ord('Q')):
break
big_frame = np.vstack((np.hstack((frame_cam1, frame_cam2)),
np.hstack((frame_cam3, frame_cam4))))
# Show a 4x4 unique frame
cv2.imshow('result', big_frame)
print('END. One or more sources ended.')
I have several images which I want to aggregate in a new image 8 image per column, 5 per row side by side with openCV in Python.
Curiously, I did not find an answer which directly addresses this question. From my spare knowledge on openCV, I would now count the width and height of the image to which the existing images should be copied, create a numpy Array with these images and change the values of the corresponding regions of Pinterest to values of each image.
Would this procedure work and more important isn't there an easier solution for this problem which haven't found?
When images are read in OpenCV's Python API, you get Numpy arrays. Numpy has vstack() and hstack() functions, which you can use to stack arrays (images) vertically and horizontally.
Let's open up two images with OpenCV:
import cv2
import numpy as np
knight = cv2.imread('knight.jpg', cv2.IMREAD_GRAYSCALE)
To use stacking in numpy, there are restriction on the image dimensions depending on the stackng axis (vertical/horizontal), so for this image, I will use cv2.resize() to get the right dimensions
queen = cv2.imread('queen.jpg', cv2.IMREAD_GRAYSCALE)
queen = cv2.resize(queen, (525, 700))
Let's make a first column by stacking 2 Knights
col_1 = np.vstack([knight, knight]) # Simply put the images in the list
# I've put 2 knights as example
Now let's make a second column with 2 Queens
col_2 = np.vstack([queen, queen])
Let's put those two columns together, but this time we'll use hstack() for that
collage = np.hstack([col_1, col_2]
Et voila, a collage of 2 x 2 which you can adapt to your needs. Note that the images passed in the stacking do need to be identical or anything, you can pass in any list of images, as long as you respect the dimensions.
In case anyone else finds it useful, here is a quick example of generalizing #bakkal's code to creating a collage out of an arbitrary number of images. It creates a collage (for simplicity, a kxk square collage, and all images are assumed to be of the same size - o.w, don't forget to resize your images!) from a directory of images, by first horizontally stacking images to create k rows, and then vertically stacking the rows to create the final canvas.
import os
def create_collages(image_dir):
image_paths = os.listdir
n = len(image_paths)
# find nearest square
collage_size = int(math.floor(math.sqrt(len(good_paths))))
# horizontally stacking images to create rows
rows = []
k = 0 # counter for number of rows
for i in range(collage_size**2):
if i % collage_size == 0: # finished with row, start new one
if k > 0:
rows.append(cur_row)
cur_row = cv2.imread(os.path.join(image_dir, image_paths[i]))
k += 1
else: # continue stacking images to current row
cur_img = cv2.imread(os.path.join(image_dir, image_paths[i]))
cur_row = np.hstack([cur_row, cur_img])
# vertically stacking rows to create final collage.
collage = rows[0]
for i in range(1, len(rows)):
collage = np.vstack([collage, rows[i]])
return collage
Resize all the images and are placed in a folder(input_dir). Here is simple a solution, collage_size parameter says how many images in the collage (r-row, c-col). It will take a random sample of r*c images if there are more images in the folder so that it can give a overall representation. I have been personally using this analyzing variety of objects from training an object detection model.
def create_collage(input_dir, collage_size):
r, c = collage_size
images_outers= []
for i in range(r):
images = []
for image_name in sample(os.listdir(input_dir), c):
print(image_name)
image = cv2.imread(os.path.join(input_dir, image_name))
images.append(image)
image_outer = np.hstack(images)
images_outers.append(image_outer)
return(np.vstack(images_outers))
This question already has an answer here:
How to capture multiple camera streams with OpenCV?
(1 answer)
Closed 10 months ago.
So I am attempting to capture from two cameras in openCV (python & windows 7). I capture from one camera just fine, youll also notice I am doing some funky stuff to the image but that doesn't matter. This is the code to attempt to use two
import cv
import time
cv.NamedWindow("camera", 1)
cv.NamedWindow("camera2", 1)
capture = cv.CaptureFromCAM(0)
capture2 = cv.CaptureFromCAM(1)
while True:
img = cv.GetMat(cv.QueryFrame(capture))
img2 = cv.GetMat(cv.QueryFrame(capture2))
dst_image = cv.CloneMat(img)
dst_image2 = cv.CloneMat(img2)
cv.ConvertScale(img, dst_image, 255, -59745.0)
cv.ConvertScale(img2, dst_image2, 255, -59745.0)
cv.ShowImage("camera", dst_image)
cv.ShowImage("camera2", dst_image2)
if cv.WaitKey(10) == 27:
cv.DestroyWindow("camera")
cv.DestroyWindow("camera2")
break
Rather simple. However it won't work. Upon trying to create the matrix from the second camera (second line of code in the loop), I am told that the capture is null. The cameras I am using are logitech and are the same model.
Side note: I also couldnt find the command to count cameras connected in python, so if someone could refer me to that I'd much appreciate it.
--Ashley
EDIT:
It might also be useful to know that windows often prompts me to choose which camera I would like to use. I can't seem to avoid this behavior. Additionally I downloaded some security like software that successful runs both cameras at once. It is not open source or anything like that. So clearly, this is possible.
I was having the same problem with two lifecam studio webcams. After a little reading, I think that problem related to overloading the bandwidth on the USB-bus. Both cameras began working if I 1.) lowered the resolution (320 x 240 each) or 2.) lowered the frame rate (~99 msec # 800 x 600). Attached is the code that got I working:
import cv
cv.NamedWindow("Camera 1")
cv.NamedWindow("Camera 2")
video1 = cv.CaptureFromCAM(0)
cv.SetCaptureProperty(video1, cv.CV_CAP_PROP_FRAME_WIDTH, 800)
cv.SetCaptureProperty(video1, cv.CV_CAP_PROP_FRAME_HEIGHT, 600)
video2 = cv.CaptureFromCAM(1)
cv.SetCaptureProperty(video2, cv.CV_CAP_PROP_FRAME_WIDTH, 800)
cv.SetCaptureProperty(video2, cv.CV_CAP_PROP_FRAME_HEIGHT, 600)
loop = True
while(loop == True):
frame1 = cv.QueryFrame(video1)
frame2 = cv.QueryFrame(video2)
cv.ShowImage("Camera 1", frame1)
cv.ShowImage("Camera 2", frame2)
char = cv.WaitKey(99)
if (char == 27):
loop = False
cv.DestroyWindow("Camera 1")
cv.DestroyWindow("Camera 2")
here is a small code:
import VideoCapture
cam0 = VideoCapture.Device(0)
cam1 = VideoCapture.Device(1)
im0 = cam0.getImage()
im1 = cam1.getImage()
im0 and im1 are PIL images. You can now use scipy to convert it into arrays as follows:
import scipy as sp
imarray0 = asarray(im0)
imarray1 = asarray(im1)
imarray0 and imarray1 are numpy 2D arrays, which you can furthere use with openCV functions.
In case you are using windows for coding, why dont you try VideoCapture module. It is very easy to use and gives a PIL image as output. You can later change it to a 2D array.