相机jetcam

配置jetcam

下载的网址

库的结构

使用traitlets来实现状态检查和参数控制,同时进行参数更新的提示。

camera.py

import traitlets
import threading
import numpy as np


class Camera(traitlets.HasTraits):
#声明几个类型
    value = traitlets.Any()#
    width = traitlets.Integer(default_value=224)
    height = traitlets.Integer(default_value=224)
    format = traitlets.Unicode(default_value='bgr8')
    running = traitlets.Bool(default_value=False)
    
    def __init__(self, *args, **kwargs):
        super(Camera, self).__init__(*args, **kwargs)
        #初始化类型。
        if self.format == 'bgr8':
            self.value = np.empty((self.height, self.width, 3), dtype=np.uint8)
        #初始化,隐藏的运行验证函数是错误。
        self._running = False
    #此处的定义是检查报错函数。类似于装饰器的写法
    def _read(self):
        """Blocking call to read frame from camera"""
        raise NotImplementedError
        
    def read(self):
        if self._running:
            raise RuntimeError('Cannot read directly while camera is running')
        self.value = self._read()
        return self.value
    
    def _capture_frames(self):
        while True:
            if not self._running:
                break
            self.value = self._read()
    #此处观察到running改变时,调用
    @traitlets.observe('running')
    #是否运行的监测
    def _on_running(self, change):
    #相机启用
        if change['new'] and not change['old']:
            # transition from not running -> running
            self._running = True
            #开始开启一个运行读取的帧的函数,此处未具体实现,在类继承的时候写。
            self.thread = threading.Thread(target=self._capture_frames)
            self.thread.start()
        #如果从真变到假
        elif change['old'] and not change['new']:
            # transition from running -> not running
            #内部决定关闭,线程终止
            self._running = False
            self.thread.join()

csi_camera.py

下面是CSI继承原相机的代码


from .camera import Camera
import atexit
#终止函数在程序终止是调用。可以在任何地方声明。
#atexit 按注册的相反顺序执行这些函数; 例如注册A、B、C,在解释器终止时按顺序C,B,A运行。

#Note:如果程序是非正常crash,或者通过os._exit()退出,注册的退出函数将不会被调用。

import cv2
import numpy as np
import threading
import traitlets


class CSICamera(Camera):
    #因为Camera继承了hastrait,所以该类拥有原属性。
    capture_device = traitlets.Integer(default_value=0)
    capture_fps = traitlets.Integer(default_value=30)
    capture_width = traitlets.Integer(default_value=640)
    capture_height = traitlets.Integer(default_value=480)
    #初始化
    def __init__(self, *args, **kwargs):
        super(CSICamera, self).__init__(*args, **kwargs)
        #此处使用opencv的接口调用了内部定义的函数,该函数返回了定义相机的gstreamer属性。且参数是类的初始化数据。
        try:
            self.cap = cv2.VideoCapture(self._gst_str(), cv2.CAP_GSTREAMER)
            #尝试读取帧
            re, image = self.cap.read()
            if not re:
                raise RuntimeError('Could not read image from camera.')
        except:
            raise RuntimeError(
                'Could not initialize camera.  Please see error trace.')
       	#此处注册了一个释放相机的函数,是opencv的函数。
        atexit.register(self.cap.release)
                
    def _gst_str(self):
        return 'nvarguscamerasrc sensor-id=%d ! video/x-raw(memory:NVMM), width=%d, height=%d, format=(string)NV12, framerate=(fraction)%d/1 ! nvvidconv ! video/x-raw, width=(int)%d, height=(int)%d, format=(string)BGRx ! videoconvert ! appsink' % (
                self.capture_device, self.capture_width, self.capture_height, self.capture_fps, self.width, self.height)
    
    def _read(self):
        re, image = self.cap.read()
        if re:
            return image
        else:
            raise RuntimeError('Could not read image from camera')

usb_camera.py

from .camera import Camera
import atexit
import cv2
import numpy as np
import threading
import traitlets


class USBCamera(Camera):
    
    capture_fps = traitlets.Integer(default_value=30)
    capture_width = traitlets.Integer(default_value=640)
    capture_height = traitlets.Integer(default_value=480)   
    capture_device = traitlets.Integer(default_value=0)
    
    def __init__(self, *args, **kwargs):
        super(USBCamera, self).__init__(*args, **kwargs)
        try:
            self.cap = cv2.VideoCapture(self._gst_str(), cv2.CAP_GSTREAMER)

            re , image = self.cap.read()
            
            if not re:
                raise RuntimeError('Could not read image from camera.')
            
        except:
            raise RuntimeError(
                'Could not initialize camera.  Please see error trace.')

        atexit.register(self.cap.release)
                
    def _gst_str(self):
        return 'v4l2src device=/dev/video{} ! video/x-raw, width=(int){}, height=(int){}, framerate=(fraction){}/1 ! videoconvert !  video/x-raw, format=(string)BGR ! appsink'.format(self.capture_device, self.capture_width, self.capture_height, self.capture_fps)
    
    def _read(self):
        re, image = self.cap.read()
        if re:
            image_resized = cv2.resize(image,(int(self.width),int(self.height)))
            return image_resized
        else:
            raise RuntimeError('Could not read image from camera')
 		

utils.py

import cv2


def bgr8_to_jpeg(value, quality=75):
    return bytes(cv2.imencode('.jpg', value)[1])

用到的依赖环境

  • atexit1
  • cv2
  • numpy
  • threading2
  • traitlets3

此处只分析了CSI相机的内容,usb的区别不大,两者仅在相机参数部分有区别,通过v4l2src,nvarguscamerasrc两个相机配置系统来确定的。
该程序有缺陷,在正常的相机调用的时候,因为是python文件,会正常的退出,调用atexit来释放掉相机的内容。但是在jupyter运行时,如果使用的是循环,就会出现相机一直占用,而块资源无法释放,会挂掉内核。即从os._exit()退出,此时不会释放相机资源导致再次调用出现问题。
解决方法:修改类,添加手动释放的调用方法,在调用时,通过按键来触发释放函数。

如果想要使用笔记本的镜头,将
CSI或者USB的cv2的接口,从流式相机调用

self.cap = cv2.VideoCapture(self._gst_str(), cv2.CAP_GSTREAMER)

改为

self.cap = cv2.VideoCapture(0

即可

如果相机未释放,通过camera.cap.release()释放。
相机初始化,可以给出帧率,长宽的一些信息。


  1. C 库函数 int atexit(void (*func)(void)) 当程序正常终止时,调用指定的函数 func。您可以在任何地方注册你的终止函数,但它会在程序终止的时候被调用。
    C链接
    Python链接 ↩︎

  2. 线程处理操作
    threading函数的使用和说明 ↩︎

  3. 使用文档 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值