List available cameras OpenCV/Python - python

I have multiple webcams connected to my PC and I would like to select one camera based on its info (name, resolution etc.). Is there a way to list all the cameras available on a PC, instead of trying all the indices in cv2.VideoCapture()?

To answer the title of your question, you can use a while loop:
import cv2
def list_ports():
"""
Test the ports and returns a tuple with the available ports and the ones that are working.
"""
is_working = True
dev_port = 0
working_ports = []
available_ports = []
while is_working:
camera = cv2.VideoCapture(dev_port)
if not camera.isOpened():
is_working = False
print("Port %s is not working." %dev_port)
else:
is_reading, img = camera.read()
w = camera.get(3)
h = camera.get(4)
if is_reading:
print("Port %s is working and reads images (%s x %s)" %(dev_port,h,w))
working_ports.append(dev_port)
else:
print("Port %s for camera ( %s x %s) is present but does not reads." %(dev_port,h,w))
available_ports.append(dev_port)
dev_port +=1
return available_ports,working_ports
It's quite easy solution to implement on your code.
Version 2
As #ketza noticed, there might be cases in which the working ports are not sequential, this version will test at least 5 non working ports before exiting the while loop:
import cv2
def list_ports():
"""
Test the ports and returns a tuple with the available ports and the ones that are working.
"""
non_working_ports = []
dev_port = 0
working_ports = []
available_ports = []
while len(non_working_ports) < 6: # if there are more than 5 non working ports stop the testing.
camera = cv2.VideoCapture(dev_port)
if not camera.isOpened():
non_working_ports.append(dev_port)
print("Port %s is not working." %dev_port)
else:
is_reading, img = camera.read()
w = camera.get(3)
h = camera.get(4)
if is_reading:
print("Port %s is working and reads images (%s x %s)" %(dev_port,h,w))
working_ports.append(dev_port)
else:
print("Port %s for camera ( %s x %s) is present but does not reads." %(dev_port,h,w))
available_ports.append(dev_port)
dev_port +=1
return available_ports,working_ports,non_working_ports

The answer is negative. OpenCV doesn't have a method for listing the available video capture devices on your system. If you look at the code you see how currently OpenCV handles invalid device indices that don't exist. For instance for MacOS here is the code:
if ( cameraNum < 0 || devices.count <= NSUInteger(cameraNum) ) {
fprintf(stderr, "OpenCV: out device of bound (0-%ld): %d\n", devices.count-1, cameraNum);
[localpool drain];
return 0;
}
You see devices.count returns the number of available devices but OpenCV doesn't have a method to return that to the user.
The relevant code for Windows is here:
if ((unsigned)m_deviceID >= m_devices.Get()->Size)
{
OutputDebugStringA("Video::initGrabber - no video device found\n");
return false;
}
Again there is no function for returning m_devices.Get()->Size to the user. The Linux code is a bit more complex.
If you're building OpenCV from code you could add a function that returns the number of available devices. Or even better submit a pull request to OpenCV with your patch.

first install package :
pip install pygrabber==0.1
code #
from pygrabber.dshow_graph import FilterGraph
graph = FilterGraph()
print(graph.get_input_devices())# list of camera device
try:
device =graph.get_input_devices().index("name camera that I want to use it ")
except ValueError as e:
device = graph.get_input_devices().index("Integrated Webcam")#use default camera if the name of the camera that I want to use is not in my list
vid=cv2.VideoCapture(device)

Related

Get Camera Device Name AND Port for OpenCV VideoStream Python?

I am currently trying to let users pick a camera for our front end software. We currently iterate through the camera devices like shown in this answer on StackOverflow. This will return us the Camera IDs:
index = 0
arr = []
while True:
cap = cv2.VideoCapture(index)
if not cap.read()[0]:
break
else:
arr.append(index)
cap.release()
index += 1
return arr
which is fine, but it would be a lot better to get a friendly device name to show the user i.e: Logitech Webcam
Does anyone know how to get the actual names of these cameras to show to the users rather than displaying with IDs?
There are two options, with the MSMF backend, you can do it here CV-camera finder, just download the .pyd file on windows (I think only works with python 3.7), or with DSHOW, which is shown on that repo's README.
Here you can directly, use this one.
pip install pygrabber
from pygrabber.dshow_graph import FilterGraph
def get_available_cameras() :
devices = FilterGraph().get_input_devices()
available_cameras = {}
for device_index, device_name in enumerate(devices):
available_cameras[device_index] = device_name
return available_cameras
print(get_available_cameras())
Output on my device,
{0: 'HD Webcam', 1: 'FHD Camera', 2: 'Intel Virtual Camera', 3: 'OBS Virtual Camera'}
Additionally, this one is for microphones also,
pip install pyaudio
import pyaudio
def get_available_michrophones() :
available_microphones = {}
pyduo = pyaudio.PyAudio()
devices_info = pyduo.get_host_api_info_by_index(0)
number_of_devices = devices_info.get('deviceCount')
for device_index in range(0, number_of_devices):
if (pyduo.get_device_info_by_host_api_device_index(0, device_index).get('maxInputChannels')) > 0:
available_microphones[device_index] = pyduo.get_device_info_by_host_api_device_index(0, device_index).get('name')
return available_microphones
print(get_available_michrophones())
Output on my device,
{0: 'Microsoft Sound Mapper - Input', 1: 'Microphone (Pusat USB Broadcast', 2: 'Microphone (FHD Camera Micropho', 3: 'Microphone (Realtek(R) Audio)'}

Why does PySpin.CameraList().GetSize() return zero devices?

Why does the following code return a cameralist with a device via PySpin.System() class and not via PySpin.CameraList() class?
The return value may differ depending on how many cameras you've attached from the manufacturer.
import PySpin
system = PySpin.System.GetInstance()
cam_list = system.GetCameras()
numCams = cam_list.GetSize() # return value >= 1
numCams2 = PySpin.CameraList().GetSize() # return value = 0
print ("No. of cams: %s - %s" % (numCams, numCams2))
Result:
No. of cams: 1 - 0
class PySpin.System(*args, **kwargs):
Here the system object GetCameras() is used to retrieve the list of interfaces and cameras available on your OS.
This only works if the static systempointer GetInstance() is used. Then the devices are loaded into the CameraList()
and therefor not empty.
class PySpin.CameraList(*args):
Used to hold a list of camera objects and does not retrieve it by itself.
Hence, numCams = len(system.GetCameras()) will also work to get the No. of devices.

Filtering packets by src mac in scapy

When I filter the packets using this filter in wireshark:
wlan.sa == 04.b1.67.14.bd.64
All goes perfect.
However, I'm trying to do it with the following python script using scapy, but it never filter by the source mac:
from scapy.all import *
from datetime import datetime
import traceback
# import MySQLdb
def getAverageSSI():
global ssiFinal
return ssiFinal
def setParams():
global window
global timestamp
global SSID
global datetime
global iterator1
window = 1
timestamp = datetime.now()
SSID='DefaultName'
iterator1 = 0
global ssiArray
ssiArray = []
def myPacketHandler(pkt) :
global SSID
global timestamp
global iterator1
global ssiArray
try :
if pkt.haslayer(Dot11) :
ssiNew = -(256-ord(pkt.notdecoded[-4:-3]))
ssiArray.append(ssiNew)
diffT=(datetime.now()-timestamp).seconds
if diffT>window:
print 'With MAC dst = %s with SSI Power= %s' %(pkt.addr1, sum(ssiArray)/len(ssiArray))
print ssiArray
ssiArray = []
timestamp=datetime.now()
except Exception as e:
print 'Exception'
print e
traceback.print_exc()
sys.exit(0)
setParams()
try:
sniff(iface="wlan1", filter="ether src 04:b1:67:14:bd:64", prn = myPacketHandler, store=0)
except Exception as e:
print e
print "Sniff AP1 Off"
I have also tried to remove the filter in sniff, and put an if like the following:
if pkt.addr1 == '04:b1:67:14:bd:64' : # mac xiaomi mi a1
# SSID = pkt.info;
ssiNew = -(256-ord(pkt.notdecoded[-4:-3]))
ssiArray.append(ssiNew)
diffT=(datetime.now()-timestamp).seconds
if diffT>window:
# query = "START TRANSACTION;"
# queryBack=cur.execute(query)
# query = "INSERT INTO RSSI VALUES(%d,\"AP1\",%d);"%(iterator1,ssiNew)
# queryBack = cur.execute(query)
print 'MAC = %s with SSI Power= %s' %(pkt.addr1, sum(ssiArray)/len(ssiArray))
ssiArray = []
# Conexion.commit()
# iterator1+=1
timestamp=datetime.now()
But it is only filtering by destination mac.
Do you know how to properly filter by mac like in the following wireshark image? (it needs to be exactly the same behaviour than in the wireshark filter):
Your second method should be working well, if you used addr2 instead of addr1
Here is how it works in 802.11 (yes it’s really messy)
Also, you should update to the github scapy version, which has support for RSSI directly (so you don’t have to parse notdecoded)
See https://github.com/secdev/scapy/archive/master.zip

Listing details of USB drives using python and udisk2

I have developed an application which uses udisks version 1 to find and list details of connected USB drives. The details include device (/dev/sdb1...etc), mount point, and free space. However, I found that modern distros has udisks2 installed by default. Here is the little code found on the other SO thread:-
#!/usr/bin/python2.7
import dbus
bus = dbus.SystemBus()
ud_manager_obj = bus.get_object('org.freedesktop.UDisks2', '/org/freedesktop/UDisks2')
om = dbus.Interface(ud_manager_obj, 'org.freedesktop.DBus.ObjectManager')
for k,v in om.GetManagedObjects().iteritems():
drive_info = v.get('org.freedesktop.UDisks2.Drive', {})
if drive_info.get('ConnectionBus') == 'usb' and drive_info.get('Removable'):
if drive_info['MediaRemovable']:
print("Device Path: %s" % k)
It produces:-
[sundar#arch ~]$ ./udisk2.py
Device Path: /org/freedesktop/UDisks2/drives/JetFlash_Transcend_8GB_GLFK4LYSFG3HZZ48
The above result is fine but how can I connect org.freedesktop.UDisks2.Block and get properties of the devices?
http://udisks.freedesktop.org/docs/latest/gdbus-org.freedesktop.UDisks2.Block.html
After lot of hit and trial, I could get what I wanted. Just posting it so that some one can benefit in the future. Here is the code:-
#!/usr/bin/python2.7
# coding: utf-8
import dbus
def get_usb():
devices = []
bus = dbus.SystemBus()
ud_manager_obj = bus.get_object('org.freedesktop.UDisks2', '/org/freedesktop/UDisks2')
om = dbus.Interface(ud_manager_obj, 'org.freedesktop.DBus.ObjectManager')
try:
for k,v in om.GetManagedObjects().iteritems():
drive_info = v.get('org.freedesktop.UDisks2.Block', {})
if drive_info.get('IdUsage') == "filesystem" and not drive_info.get('HintSystem') and not drive_info.get('ReadOnly'):
device = drive_info.get('Device')
device = bytearray(device).replace(b'\x00', b'').decode('utf-8')
devices.append(device)
except:
print "No device found..."
return devices
def usb_details(device):
bus = dbus.SystemBus()
bd = bus.get_object('org.freedesktop.UDisks2', '/org/freedesktop/UDisks2/block_devices%s'%device[4:])
try:
device = bd.Get('org.freedesktop.UDisks2.Block', 'Device', dbus_interface='org.freedesktop.DBus.Properties')
device = bytearray(device).replace(b'\x00', b'').decode('utf-8')
print "printing " + device
label = bd.Get('org.freedesktop.UDisks2.Block', 'IdLabel', dbus_interface='org.freedesktop.DBus.Properties')
print 'Name od partition is %s'%label
uuid = bd.Get('org.freedesktop.UDisks2.Block', 'IdUUID', dbus_interface='org.freedesktop.DBus.Properties')
print 'UUID is %s'%uuid
size = bd.Get('org.freedesktop.UDisks2.Block', 'Size', dbus_interface='org.freedesktop.DBus.Properties')
print 'Size is %s'%uuid
file_system = bd.Get('org.freedesktop.UDisks2.Block', 'IdType', dbus_interface='org.freedesktop.DBus.Properties')
print 'Filesystem is %s'%file_system
except:
print "Error detecting USB details..."
The complete block device properties can be found here http://udisks.freedesktop.org/docs/latest/gdbus-org.freedesktop.UDisks2.Block.html
Edit
Note that the Block object does not have ConnectionBus or Removable properties. You will have to change the code to remove references to Drive object properties for the code to work.
/Edit
If you want to connect to Block, not Drive, then instead of
drive_info = v.get('org.freedesktop.UDisks2.Drive', {})
try
drive_info = v.get('org.freedesktop.UDisks2.Block', {})
Then you can iterate through drive_info and output it's properties. For example, to get the Id property, you could:
print("Id: %s" % drive_info['Id'])
I'm sure that there is a nice pythonic way to iterate through all the property key/value pairs and display the values, but I'll leave that to you. Key being 'Id' and value being the string stored in drive_info['Id']. Good luck

Filtering USB HID Columns in Python

Something I can't seem to find the answer for. Please bare in mind I am not an expert so I may be missing simple, perhaps how I'm printing the device I want.
I am trying to store a device version number (dvm from herein), off a USB device. The problem is the USB device has two columns for reporting, feature and output.
So when I print the device I receive two sets of print statements.
#
def device(target_usage, target_vendor_id):
hidDevice = False
all_devices = hid.HidDeviceFilter(vendor_id = target_vendor_id).get_devices()
print "\n", all_devices
if len(all_devices) == 0:
# Exit if no devices found, report error.
hidDevice = False
time.sleep(0.2)
print "No devices can be detected, please check device is connected."
sys.exit(1)
return
elif len(all_devices) > 2:
# announce there are more than 1 device connected to prevent conflicting upgrades
hidDevice = True
time.sleep(0.2)
print "Too many devices connected, ensure the only device connected is the device needed to test."
sys.exit(1)
else:
# loop through all devices
for device in all_devices:
try:
device.open()
# print device details
device_name = unicode("=== INFO: Found %s %s (vID=[%04x], pID=[%04x], version number [%04x]) ===" % \
(device.vendor_name, device.product_name, device.vendor_id, device.product_id, device.version_number))
dvm = unicode("%04x" % \
(device.version_number))
print dvm;
print device_name;
finally:
device.close()
hidDevice = True
return hidDevice
#
When this function is called it will print all devices but I end up with the following result (Modified pids/vids etc for privacy issues.)
[HID device (vID=0x0000, pID=0x0000, v=0x0000); Make; Model, Path: \?\hid#vid_0000&pid_0000&col01#7&00000000&1&0000#{00000000-0000-0000-0000-000000000000}, HID device (vID=0x0000, pID=0x0000, v=0x0000); Make; Model, Path: \?\hid#vid_0000&pid_0000&col02#7&00000000&1&0000#{00000000-0000-0000-0000-000000000000}
The important part is the col01 and col02.
How can I filter that second enumerated HID device out?
Included the following code.
for report in device.find_output_reports():
if target_usage in report:
# add to target list
Targets.append(device)
finally:
device.close()
for item in Targets:
try:
item.open(output_only = True)
dvm = unicode("%04x" % \
(device.version_number))
print dvm
finally:
item.close()
Problem resolved.

Categories