精华内容
下载资源
问答
  • linux检测目录下文件变化

    千次阅读 2017-10-18 18:09:08
    当摄像头动态检测变化后会保存一段时间视频画面并写入某个目录下,而我需要提供一个api去获取是否有新文件生成。经过查阅网友分享得知,在Linux 2.6.13内核中引入inotify接口用于检测文件及目录变化。本文

    Linux 检测目录下文件变化api

    前排致谢:
    http://blog.csdn.net/myiloveuuu/article/details/53296619

    最近要实现一个需求:
    当摄像头动态检测变化后会保存一段时间视频画面并写入到某个目录下,而我需要提供一个api去获取是否有新文件生成。经过查阅网友分享得知,在Linux 2.6.13内核中引入inotify接口用于检测文件及目录变化。

    本文可能有所疏漏,可参阅:man inotify

    1 代码

    先上代码,再逐步分析。

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/inotify.h>
    #include <unistd.h>
    static void *PIRThread(void *id)
    {
    int fd = 0;  
    char data[255] = {0};  
    char* eventptr;
    int step = 0;
    struct inotify_event event;
    
    fd = inotify_init1(IN_NONBLOCK);
    int step = 0;
    inotify_add_watch(fd, "/home/xx.xx/work/v50/IISC/media",IN_CREATE|IN_MOVED_TO);//监听是否有新文件 
    while(1)
    {
        readLength = read(fd, data, 255);
        if(readLength > 0)
        {
    //解析事件描述结构体
             cout <<  readLength << endl;
            eventptr = data;
            event.wd = *((int*)eventptr);
            step +=sizeof(int);
            //eventptr += sizeof(int);
            event.mask = *((uint32_t*)(eventptr+step));
            step  += sizeof(uint32_t);
            event.cookie  = *((uint32_t*)(eventptr+step));
            step += sizeof(uint32_t);
            event.len  = *((uint32_t*)(eventptr+step));
            step += sizeof(uint32_t);
            string filename(eventptr+step, event.len);
            step = 0;
    
            cout << "wd:"<<event.wd << endl;
            cout << "mask:"<<event.mask << endl;
            cout << "cookie:"<<event.cookie  << endl;
            cout << "len:" <<event.len<< endl;
            cout << "filename:" <<filename << endl;
    
            if(event.mask == IN_CREATE)
                cout <<"new file was created:"<< event.mask << endl;
            else if(event.mask == IN_MOVED_TO)
                cout <<"new file was move to mydir"<< event.mask << endl;
        } 
        sleep(1);
    }
    pthread_exit(0);
    }
    

    2 代码分析

    代码单独开辟一个线程用于检测文件下文件变化,并每秒读取一次。

    2.1 inotify_init1(int flags)

    可传入参数:IN_NONBLOCK 不阻塞 ,IN_CLOEXEC 阻塞

    初始化inotify实例并返回一个描述符。

    fd = inotify_init1(IN_NONBLOCK);
    

    即为不阻塞方式检测文件变化。
    如果参数CLOEXEC 就会阻塞在 read函数,直到检测成功才接着往下执行。

    2.2 int inotify_add_watch(int fd, const char *pathname, uint32_t mask); ###

    参数:

    • fd是inotify文件描述符,inotify_init()的返回值
    • pathname是要监听的文件的路径
    • mask是指定要监视哪些事件(值在2.3中)
      返回:
      返回值是一个inotify标识(wd),即该监听事件标志与fd不是同一个东西。

      inotify_add_watch(fd, “/home/jw.li/work/v50/IISC/media”,IN_CREATE|IN_MOVED_TO);

    2.3 相应事件

    • IN_ACCESS: 文件被访问
    • IN_ATTRIB:元数据被改变,例如权限、时间戳、扩展属性、链接数、UID、GID等
    • IN_CLOSE_WRITE:关闭打开写的文件
    • IN_CLOSE_NOWRITE: 和IN_CLOSE_WRITE刚好相反,关闭不是打开写的文件
    • IN_CREATE:这个是用于目录,在监控的目录中创建目录或文件时发生
    • IN_DELETE:这个也是用于目录,在监控的目录中删除目录或文件时发生
    • IN_DELETE_SELF:监控的目录或文件本身被删除
    • IN_MODIFY:文件被修改,这种事件会用到inotify_event中的cookie。
    • IN_MOVE_SELF:监控的文件或目录本身被移动
    • IN_MOVED_FROM: 从监控的目录中移出文件
    • IN_MOVED_TO:向监控的目录中移入文件
    • IN_OPEN: 文件被打开

    2.4 read(fd, buf, count); 读取事件

    参数:

    • fd是inotify文件描述符,inotify_init()的返回值
    • buf用于读取inotify事件结构的buf(自己开辟传入)
    • Count 读取buffer大小(s)

    返回:

    • 监听时间均未发生时,返回值为-1
    • 监听事件发生时,返回值为inotify事件结构大小

      readLength = read(fd, data, 255);

    即如果监听事件发生,data值为struct inotify_event event结构体数据,readLength为 结构体数据大小,返回,truct inotify_event event内容在2.5中介绍。

    2.5 inotify_event

    struct inotify_event {
       int  wd;   /* Watch descriptor */
       uint32_t mask; /* Mask of events */
       uint32_t cookie;   /* Unique cookie associating related  
     events (for rename(2)) */
       uint32_t len;  /* Size of name field */
       char name[];   /* Optional null-terminated name */
    };  
    

    其中wd是inotify标识符,inotify_add_watch()的返回值;

    • mask就是发生的事件掩码;
    • cookie这个好像只在rename中使用,
    • len 原本以为是文件名长度但测试发现并不是。
    • name就是检测改变的文件的名字

    解析:
    我们可以通过指针按照结构体中各元素大小解析出数据

            char* eventptr;
            int step = 0;
            struct inotify_event event;
    
            eventptr = data;
            event.wd = *((int*)eventptr);
            step +=sizeof(int);
            //eventptr += sizeof(int);
            event.mask = *((uint32_t*)(eventptr+step));
            step  += sizeof(uint32_t);
            event.cookie  = *((uint32_t*)(eventptr+step));
            step += sizeof(uint32_t);
            event.len  = *((uint32_t*)(eventptr+step));
            step += sizeof(uint32_t);
            string filename(eventptr+step, event.len);
            step = 0;
    

    2.6 通过解析出的 event.mask与事件做对比对各事件进行处理。

    if(event.mask == IN_CREATE)
    cout <<”new file was created:”<< event.mask << endl;
    else if(event.mask == IN_MOVED_TO)
    cout <<”new file was move to mydir”<< event.mask << endl;

    sample:
    linux 环境
    https://github.com/CollapsarLi/li_checkfilechange_sample.git

    git clone https://github.com/CollapsarLi/li_checkfilechange_sample.git;
    cd cd li_checkfilechange_sample/
    阅读 readme

    展开全文
  • motion 非常强大,可以监测画面变化后保存成 mpeg 或 jpeg,还可以运行成 http 服务器模式。但是树莓派放在家里,从外面访问有时也会访问不了(比如 IP 变了等原因)。其实使用 Python + OpenCV 打造一个对运动画面...

    大家用树莓派来做监控,文章里面一般都是使用 fswebcam 或 motion。motion 非常强大,可以监测画面变化后保存成 mpeg 或 jpeg,还可以运行成 http 服务器模式。但是树莓派放在家里,从外面访问有时也会访问不了(比如 IP 变了等原因)。其实使用 Python + OpenCV 打造一个对运动画面能够进行简单判断的程序并不困难。下面的程序每个 0.5 秒做一下检测,如果画面有变化就保存下来,并且将其上传到百度的云存储中。为了保证隐私,上传之前还可以给照片做 AES 加密,只有知道密码才能查看照片的内容。不过,OpenCV 在树莓派上跑还是挺吃力的,CPU 基本保持在 6-70% 左右。


    注册为百度开发者(http://developer.baidu.com/)就可以创建自己的百度云存储空间了。然后在云存储中新建一个 bucket,把代码中所有的 'homepics' 替换成你的 bucket 名称。


    要运行这个程序,在树莓派上需要安装有 python2.7 和 PyCrypto、OpenCV、numpy、requests 模块。

    在命令行运行:cv.py -d 0 -i /home/img -p qwerty123456qwerty123456 -u bcs:[app_key]:[sk]

    如果没有 -p 参数照片就不加密,没有 -u 参数就不会存到百度云上。


    另外,还做了一个 web 站点,把 bucket 中图片都列出来,用浏览器就可以直接查看:http://eaho.sinaapp.com/


    #coding: cp936
    import os, time, datetime, multiprocessing, urllib, base64, hashlib, hmac, argparse, tempfile
    import cv2, numpy, requests
    from Crypto.Cipher import AES
    from Crypto.Util import Counter
    
    class Bcs:
        def __init__(self, ak, sk):
            self.base_url = 'http://bcs.duapp.com'
            self.ak = ak
            self.sk = sk
            self.MAX_FILE_SIZE = 250000
            
        def getContent(self, method = 'GET', bucket = '', obj = '', time = None, ip = None, size = None):
            content = 'Method=%s\n' % method
            content += 'Bucket=%s\n' % bucket
            content += 'Object=/%s\n' % obj
            
            flag = 'MBO'
            if time:
                flag += 'T'
                content += 'Time=%d\n' % time
            if ip:
                flag += 'I'
                content += 'Ip=%s\n' % ip
            if size:
                flag += 'S'
                content += 'Size=%d\n' % size
                
            return flag, flag + '\n' + content
    
        def getSignature(self, content):
            return urllib.quote_plus(base64.encodestring(hmac.new(self.sk, content, hashlib.sha1).digest())[:-1])
            
        def getUrl(self, flag, signature, bucket = '', obj = '', time = None, size = None, oparam = ''):
            if obj:
                bucket += '/%s' % obj
                
            url = []
            param = ''
            if time:
                url.append('time=%d' % time)
            if size:
                url.append('size=%d' % size)
            if url:
                param = '&' + '&'.join(url)
            if oparam:
                param += '&' + oparam
            
            
            return '%s/%s?sign=%s:%s:%s%s' % (self.base_url, bucket, flag, self.ak, signature, param)
            
        def upload(self, path, bucket):
            name = os.path.split(path)
            filename = name[1]
            file_size = self.MAX_FILE_SIZE
            
            timestamp = int(time.time() + 60)
            
            flag, content = self.getContent(method = 'POST', bucket = bucket, obj = filename, time = timestamp, size = file_size)
            signature = self.getSignature(content)
            url = self.getUrl(flag, signature, bucket, filename, timestamp, file_size)
            
            print self.postFile(url, path)
            
        def upload2(self, filename, bucket, text):
            file_size = self.MAX_FILE_SIZE
            
            timestamp = int(time.time() + 60)
            
            flag, content = self.getContent(method = 'POST', bucket = bucket, obj = filename, time = timestamp, size = file_size)
            signature = self.getSignature(content)
            url = self.getUrl(flag, signature, bucket, filename, timestamp, file_size)
            
            print self.postFileContent(url, text)
    
        def postFile(self, url, path):
            f = open(path, 'rb')
            files = {'file': f}
            result = requests.post(url, files=files)
            f.close()
            return result.text
            
        def postFileContent(self, url, content):
            files = {'file': content}
            result = requests.post(url, files=files)
            return result.text
            
        def listBucket(self):
            flag, content = self.getContent(method = 'GET')
            signature = self.getSignature(content)
            url = self.getUrl(flag, signature)
            
            result = requests.get(url).json()
            return result
            
        def listObject(self, bucket, start = 0, limit = 20):
            flag, content = self.getContent(method = 'GET', bucket = bucket)
            signature = self.getSignature(content)
            url = self.getUrl(flag, signature, bucket = bucket, oparam = 'start=%d&limit=%d' % (start, limit))
            
            result = requests.get(url).json()
            return result
            
        def getImg(self, bucket, obj):
            flag, content = self.getContent(method = 'GET', bucket = bucket, obj = obj)
            signature = self.getSignature(content)
            url = self.getUrl(flag, signature, bucket, obj)
            
            result = requests.get(url)
            return result.content
        
    
    class MotionDetect:
        def __init__(self, device = 0, base_path = '', skey = '', upload_mode = ''):
            self.mhi = None
            self.lastImg = None
            self.diff_threshold = 30
            self.MHI_DURATION = 0.5
            self.MAX_TIME_DELTA = 0.25
            self.MIN_TIME_DELTA = 0.05
            
            self.device = device
            self.skey = skey
            self.upload_mode = upload_mode
            
            if base_path == '':
                self.base_path = tempfile.gettempdir()
            else:
                self.base_path = base_path
            
            self.pipe = multiprocessing.Pipe()
            self.worker = None
    
        def update(self, img):
            h, w = img.shape[:2]
            if self.mhi == None:
                self.mhi = numpy.zeros((h, w), numpy.float32)
            
            if self.lastImg == None:
                self.lastImg = img
                
            frame_diff = cv2.absdiff(img, self.lastImg)
            gray_diff = cv2.cvtColor(frame_diff, cv2.COLOR_BGR2GRAY)
            ret, silh = cv2.threshold(gray_diff, self.diff_threshold, 1, cv2.THRESH_BINARY)
            
            timestamp = cv2.getTickCount() / cv2.getTickFrequency()
            cv2.updateMotionHistory(silh, self.mhi, timestamp, self.MHI_DURATION)
            mask, orient = cv2.calcMotionGradient(self.mhi, self.MAX_TIME_DELTA, self.MIN_TIME_DELTA, apertureSize=5)
            segmask, seg_bounds = cv2.segmentMotion(self.mhi, timestamp, self.MAX_TIME_DELTA)
    
            self.lastImg = img
            
            count = 0
            for i, rect in enumerate([(0, 0, w, h)] + list(seg_bounds)):
                x, y, rw, rh = rect
                area = rw*rh
                if area < 64**2:
                    continue
                
                count += 1
            return count
            
        def encrypt(self, img, timestamp):
            ctr = Counter.new(128)
            aes = AES.new(self.skey, AES.MODE_CTR, counter = ctr)
            
            ret, text = cv2.imencode('.jpg', img, [int(cv2.IMWRITE_JPEG_QUALITY), 80])
            
            cbin = aes.encrypt(text)
            
            filename = os.path.join(self.base_path, timestamp + '.jpg')
            
            outfile = open(filename, 'wb')
            outfile.write(cbin)
            outfile.close()
            
            return filename
            
        def encrypt2(self, img):
            ret, text = cv2.imencode('.jpg', img, [int(cv2.IMWRITE_JPEG_QUALITY), 80])
            
            if self.skey != '':
                ctr = Counter.new(128)
                aes = AES.new(self.skey, AES.MODE_CTR, counter = ctr)
                text = aes.encrypt(text)
            return text
            
        def decrypt(self, filename):
            cbin = open(filename, 'rb').read()
            
            ctr = Counter.new(128)
            aes = AES.new(self.skey, AES.MODE_CTR, counter = ctr)
            text = aes.decrypt(cbin)
            
            open(filename + '.jpg', 'wb').write(text)
            
            return filename + '.jpg'
    
        def detect(self):
            cap = cv2.VideoCapture(self.device)
            time.sleep(2)
    
            while True:
                s = time.clock()
                
                timestamp = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')[:-3]
                ret, img = cap.read()
                count = self.update(img)
                
                if count > 3:
                    cbin = self.encrypt2(img)
                    filename = os.path.join(self.base_path, timestamp + '.jpg')
                    print filename
                    outfile = open(filename, 'wb')
                    outfile.write(cbin)
                    outfile.close()
                    
                    self.processImage(timestamp)
                    print time.clock() - s
                
                time.sleep(0.2)
                
            if self.worker.is_alive():
                self.worker.join()
                
        def processImage(self, timestamp):
            if self.worker == None or self.worker.is_alive() == False:
                print 'start new process'
                self.worker = multiprocessing.Process(target = self.processWorker, args = (self.pipe[0],))
                self.worker.start()
                
            print 'send...', timestamp
            self.pipe[1].send(timestamp)
                
        def processWorker(self, pipe):
            while pipe.poll(10):
                timestamp = pipe.recv()
                print 'processing... %s' % timestamp
    
                if self.upload_mode != '':
                    if self.upload_mode.startswith('bcs:'):
                        _, ak, sk = self.upload_mode.split(':')
                        bcs = Bcs(ak, sk)
                        
                        try:
                            filename = os.path.join(self.base_path, timestamp + '.jpg')
                            bcs.upload(, 'homepics')
                            os.remove(filename)
                            print 'uploaded ' + timestamp
                        except:
                            print 'upload failed: ' + timestamp
                
    if __name__ == '__main__':
        parser = argparse.ArgumentParser()
        parser.add_argument('-d', action = 'store', dest = 'device_index', default = 0, type = int, help = 'video device index, default is 0.')
        parser.add_argument('-D', action = 'store', dest = 'decrypt', default = '', help = 'decrypt file.')
        parser.add_argument('-i', action = 'store', dest = 'image_path', default = '', help = 'image storage directory.')
        parser.add_argument('-p', action = 'store', dest = 'pwd', default = '', help = 'the password for encrypt the image file. the file will not be encrypted if pwd is null.')
        parser.add_argument('-u', action = 'store', dest = 'upload_mode', default = '', help = '''store the image to Internet storage service. 
    Baidu Cloud Storage. parame --> bcs:app_key(ak):screct_key(sk)
    Baidu PCS. [unsupported]
    Sina vdisk. [unsupported]
    Huawei dbank. [unsupported]
    ''')
        args = parser.parse_args()
        
        motion = MotionDetect(args.device_index, args.image_path, args.pwd, args.upload_mode)
        if args.decrypt != '':
            if args.pwd != '':
                motion.decrypt(args.decrypt)
            else:
                print 'decrypt need a password(-p pwd)'
        else:
            motion.detect()
        
        


    展开全文
  •  4) 创新性的分布式智能视频检测功能,远程客户端也能检测到画面变化,直接在本地报警。  MoviGuard典型用途(不限于以下几种):  1) 想时刻看家中宝宝的同学。  2) 偶尔出门时, 担心家里安全的同学。 ...
  • 使用 OpenCV 进行运动检测

    千次阅读 2018-06-07 09:41:34
    最近在做一个项目的时候需要检测摄像头拍摄范围内的图像是否有变化,即需要进行运动检测,在检测到运动之后录制 5 秒的视频存档。 在查阅了一些资料之后,发现了一种效果不错的方法(原始文章见参考内容 1),该...

    概览

    最近在做一个项目的时候需要检测摄像头拍摄范围内的图像是否有变化,即需要进行运动检测,在检测到运动之后录制 5 秒的视频存档。
    在查阅了一些资料之后,发现了一种效果不错的方法(原始文章见参考内容 1),该方法只进行运动检测,不进行追踪。该方法的主要思路就是计算连续帧之间的差距,如果该差距较大,我们就认为画面的内容发生了变化。其中为了避免假阳性,该方法计算了帧差的标准差。
    算法的主要流程如下:

    1. 计算帧间的距离(Pythagorean distance)
    2. 在计算出来的距离矩阵上应用高斯模糊
    3. 使用一定的阈值进行过滤
    4. 计算标准差
    5. 标准差大于一定的阈值,认为检测到了运动,输出信息

    本文将给出 PythonC++ 两种语言的实现。

    运行环境

    操作系统:ARMBIAN 5.38 stable Ubuntu 16.04.3 LTS 3.4.113-sun8i
    编程环境:Python 2.7.12, OpenCV 3.3.0

    Python 实现

    import numpy as np
    import cv2
    
    sdThresh = 10
    font = cv2.FONT_HERSHEY_SIMPLEX
    
    def distMap(frame1, frame2):
        """outputs pythagorean distance between two frames"""
        frame1_32 = np.float32(frame1)
        frame2_32 = np.float32(frame2)
        diff32 = frame1_32 - frame2_32
        norm32 = np.sqrt(diff32[:,:,0]**2 + diff32[:,:,1]**2 + \
                 diff32[:,:,2]**2)/np.sqrt(255**2 + 255**2 + 255**2)
        dist = np.uint8(norm32*255)
        return dist
    
    cv2.namedWindow('frame')
    cv2.namedWindow('dist')
    
    #capture video stream from camera source. 0 refers to first camera, 1 referes to 2nd and so on.
    cap = cv2.VideoCapture(0)
    
    _, frame1 = cap.read()
    _, frame2 = cap.read()
    
    facecount = 0
    while(True):
        _, frame3 = cap.read()
        rows, cols, _ = np.shape(frame3)
        cv2.imshow('dist', frame3)
        dist = distMap(frame1, frame3)
    
        frame1 = frame2
        frame2 = frame3
    
        # apply Gaussian smoothing
        mod = cv2.GaussianBlur(dist, (9,9), 0)
    
        # apply thresholding
        _, thresh = cv2.threshold(mod, 100, 255, 0)
    
        # calculate st dev test
        _, stDev = cv2.meanStdDev(mod)
    
        cv2.imshow('dist', mod)
        cv2.putText(frame2, "Standard Deviation - {}".format(round(stDev[0][0],0)), \
                    (70, 70), font, 1, (255, 0, 255), 1, cv2.LINE_AA)
        if stDev > sdThresh:
                print("Motion detected.. Do something!!!");
    
        cv2.imshow('frame', frame2)
        if cv2.waitKey(1) & 0xFF == 27:
            break
    
    cap.release()
    cv2.destroyAllWindows()
    

    C++ 实现

    复制下面的代码,保存为 motion.cpp,运行下面的编译命令即可

    g++ motion.cpp -o motion `pkg-config --cflags --libs opencv`
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <cstdio>
    #include <cmath>
    #include <cstdlib>
    #include"omp.h"
    
    using namespace cv;
    #define MOTION_THRESH 10
    
    void distMap(const Mat &a, const Mat &b, Mat &out){
        #pragma omp parallel
        for(int y = 0; y < a.rows; ++y){
            for(int x = 0; x < a.cols; ++x){
                int summary = 0;
                for(int z = 0; z < a.dims; ++z){
                    summary += pow(a.at<Vec3b>(y, x)[z] - b.at<Vec3b>(y, x)[z], 2);
                }
                out.at<uchar>(y, x) = (int) (255.0 * sqrt(summary) / sqrt(3 * pow(255, 2)));
            }
        }
    }
    
    
    int main(int argc, char **argv){
        printf("=========== initializing ==========\n");
    
        int device = 0;
        int motion_count = 0;
    
        if(argc == 2) {
            device = atoi(argv[1]);
        }
    
        printf("device id %d\n", device);
    
        VideoCapture myCamera(device);
    
        myCamera.set(CV_CAP_PROP_FRAME_WIDTH, 640);
        myCamera.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    
        if (!myCamera.isOpened()){
            printf("cannot open camera\n");
            return 0;
        }else{
            printf("%s\n", "===========start camera==========");
        }
    
        Mat preVideoFrame, curVideoFrame, nextVideoFrame;
    
        for(int i = 0; i < 5; i++) {
            myCamera >> preVideoFrame;
        }
    
        myCamera >> preVideoFrame;
        myCamera >> curVideoFrame;
    
    
        Mat dist(preVideoFrame.rows, preVideoFrame.cols, CV_8UC1);
        Mat blurDist(preVideoFrame.rows, preVideoFrame.cols, CV_8UC1);
        Mat threDist(preVideoFrame.rows, preVideoFrame.cols, CV_8UC1);
        Mat meanDist(preVideoFrame.rows, preVideoFrame.cols, CV_8UC1);
        Mat stdDist(1, 1, CV_8UC1);
    
        char text[100] = {0};
    
        int key = 0;
        while (key != 27){
            myCamera >> nextVideoFrame;
    
            // key = waitKey(1);
            // continue;
    
            if (!preVideoFrame.empty() && !curVideoFrame.empty() && !nextVideoFrame.empty()){
                distMap(preVideoFrame, nextVideoFrame, dist);
    
                curVideoFrame.copyTo(preVideoFrame);
                nextVideoFrame.copyTo(curVideoFrame);
    
                blur(dist, blurDist, Size(3, 3));
    
                threshold(blurDist, threDist, 100, 255, THRESH_BINARY);
    
                meanStdDev(threDist, meanDist, stdDist);
    
                sprintf(text, "Standard Deviation - %d", stdDist.at<uchar>(0, 0));
    
                cv::putText(curVideoFrame, text, Point(70, 70), FONT_HERSHEY_SIMPLEX, 
                            1, (255, 0, 255), 1, LINE_AA);
    
                if(stdDist.at<uchar>(0, 0) > MOTION_THRESH) {
                    printf("%d motion detected\r", stdDist.at<uchar>(0, 0));
                    fflush(stdout);
                }
    
                imshow("distMap", blurDist);
                imshow("preview", curVideoFrame);
    
            }
    
            key = waitKey(1);
        }
    
        myCamera.release();
        printf("%s\n", "===========release camera==========");
    
        return 0;
    }
    

    参考内容

    1. Motion detection using OpenCV
    展开全文
  • 本项目是一个很奇特的项目源码,就是通过摄像头来获得心率,搜了一下这个技术真不是噱头,据说在iPhone早有实现,主要原理是:当打开软件时,手机的闪光...这样毛细血管的搏动就能通过画面明度的周期性变化反映出来。 
  • 边缘检测,就是找到原始图像中画面出现跳变的地方。这里的跳变,可以理解为相邻像素的像素值出现了较大的变化,而梯度方向为灰度最大变化率的方向(求导解决)。  在实际的图像分割中,往往只用一阶和二阶导数,...

    边缘检测是图像处理和计算机视觉中,尤其是特征提取中的一个研究领域。图像边缘检测大幅度的减少了数据量,并且剔除了可以认为不相关的信息,保留了图像重要的结构属性。边缘检测,就是找到原始图像中画面出现跳变的地方。这里的跳变,可以理解为相邻像素的像素值出现了较大的变化,而梯度方向为灰度最大变化率的方向(求导解决)。

      在实际的图像分割中,往往只用到一阶和二阶导数,虽然原理上,可以用更高阶的导数,但是因为噪声的影响,在纯粹二阶的导数操作中就会出现对噪声的敏感现象,三阶以上的导数信息往往失去了应用价值。二阶导数还可以说明灰度突变的类型。在某些情况下,如灰度变化均匀的图像,只利用一阶导数可能找不到边界,此时二阶导数就能提供很有用的信息。二阶导数对噪声也比较敏感,解决的方法是先对图像进行平滑滤波,消除部分噪声,再进行边缘检测。不过,利用二阶导数信息的算法是基于过零检测的,因此得到的边缘点数比较少,有利于后继的处理和识别工作。

    边缘检测算子可分为以下几种:

    1. 一阶微分算子:Roberts交叉梯度算子 、Prewitt算子、Sobel算子、Scharr算子。
    2. 二阶微分算子:Laplacian算子、 LOG算子
    3. 非微分边缘检测算子:canny算子。

    下面主要将canny算子和sobel算子的原理,其他算子只写出了实现函数.

    1. sobel算子

    1.1 概念:

    索贝尔算子(Sobeloperator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量。

    1.2 原理:

    Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘.Sobel算子的俩个梯度矩阵Gx和Gy, Gx 用来计算横向的梯度, Gy 用来计算纵向的梯度。

    具体公式如下:

    原图中的作用点像素值通过卷积之后为:

    可以化简成(为了提升效率):

    如果梯度G大于阈值,这认为(x, y)是边缘点.

    Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。Sobel算子检测方法对灰度渐变和噪声较多的图像处理效果较好,sobel算子对边缘定位不是很准确,图像的边缘不止一个像素;当对精度要求不是很高时,是一种较为常用的边缘检测方法。

    1.3  优缺点:

    优点:计算简单,速度很快;

    缺点:计算方向单一,对复杂纹理的情况显得乏力;直接用阈值来判断边缘点欠合理解释,会造成较多的噪声点误判。

    1.4 实现函数- cv2.sobel()

    • 参数如下:cv2.Sobel(src, ddepth, dx, dy[, ksize[, scale[, delta[, borderType]]]])
    • 参数说明:
    • src:输入图像
    • ddepth: 输出图像的深度(可以理解为数据类型),是指存储每个像素值所用的位数,-1表示与原图像相同的深度
    • dx,dy:当组合为dx=1,dy=0时求x方向的一阶导数,当组合为dx=0,dy=1时求y方向的一阶导数(如果同时为1,通常得不到想要的结果)
    • ksize:(可选参数)Sobel算子的大小,必须是1,3,5或者7,默认为3。
    • scale:(可选参数)将梯度计算得到的数值放大的比例系数,效果通常使梯度图更亮,默认为1
    • delta:(可选参数)在将目标图像存储进多维数组前,可以将每个像素值增加delta,默认为0
    • borderType:(可选参数)决定图像在进行滤波操作(卷积)时边沿像素的处理方式,默认为BORDER_DEFAULT

    2. canny算子

    2.1 原理

    Canny边缘检测是一种比较新的边缘检测算子,具有很好地边缘检测性能,该算子功能比前面几种都要好,但是它实现起来较为麻烦,Canny算子是一个具有滤波,增强,检测的多阶段的优化算子,在进行处理前,Canny算子先利用高斯平滑滤波器来平滑图像以除去噪声,Canny分割算法采用一阶偏导的有限差分来计算梯度幅值和方向,在处理过程中,Canny算子还将经过一个非极大值抑制的过程,最后Canny算子还采用两个阈值来连接边缘(高低阈值输出二值图像)。

    2.2 算法步骤

    1. 用高斯滤波器平滑图像


    高斯滤波器是一种线性滤波器,能够有效的抑制噪声,平滑图像。

    计算方式如下:

     

                                                                                            原始坐标                                        带入高斯函数                               归一化

    从第二张图可以看出,中心点处的值最大,离中心点越近的值越大,这符合高斯分布;之后进行归一化,就得到高斯滤波核;再进行卷积操作。

    2. 用一阶偏导有限差分计算梯度幅值和方向.

    可选用的模板:sobel算子、Prewitt算子、Roberts模板等等;

    一般采用sobel算子,OpenCV也是如此,利用sobel水平和垂直算子与输入图像卷积计算dx、dy:

    Gx是对水平方向求梯度值, Gy是对垂直方向求梯度值(计算方式就是卷积操作,只不过是在俩个方向上做卷积)。

    使用以下公式计算梯度幅值和方向:

                                                                              

    梯度方向近似到四个可能角度之一(一般 0, 45, 90, 135)

    求出θ, θ 的值可能不是这些角度, 就看θ离哪条直线近, 则这条直线的角度就是θ.这样分的好处是:方便了后面非极大值抑制的计算。因为图像中像素点的分布是离散的,这样四个方向和他们的反方向上都有像素点。

    梯度幅值:变换率最大  梯度方向:是后面准确的找出细化边缘的前提。

    这步其实就是图像增强,并没有找到真正的边。

    3. 对梯度幅值进行非极大值抑制(NMS)

    将某点的幅值和沿着梯度方向的俩个幅值进行比较,若该点的幅值大于这俩个方向上的幅值,则保留;否则置为0.这样就可以得到局部最大值点,也就是极大值,则认为这个像素点是边缘点,就可以得到细化的边.

    如图所示,g1、g2、g3、g4都代表像素点,很明显它们是c的八领域中的4个,左图中c点是我们需要判断的点,蓝色的直线是它的梯度方向,也就是说c要是局部极大值,它的梯度幅值M需要大于直线与g1g2和g2g3的交点,dtmp1和dtmp2处的梯度幅值。但是dtmp1和dtmp2不是整像素,而是亚像素,也就是坐标是浮点的,那怎么求它们的梯度幅值呢?利用线性插值,例如dtmp1在g1、g2之间,g1、g2的幅值都知道,我们只要知道dtmp1在g1、g2之间的比例,就能得到它的梯度幅值,而比例是可以靠夹角计算出来的,夹角又是梯度的方向。比如,假设g1处的幅值是1, g2处的幅值是4,θ为60°,则g1和g2的距离是d1 = 3,dTmp1和g2的距离为√3 ,则可求得dTmp1处的幅值为 4 - √3

    线性插值: 线性插值是一种针对一维数据的插值方法,它根据一维数据序列中需要插值的点的左右邻近两个数据点来进行数值的估计。当然了它不是求这两个点数据大小的平均值(当然也有求平均值的情况),而是根据到这两个点的距离来分配它们的比重的。

    4. 用双阈值算法检测和连接边缘(滞后边界跟踪)

    滞后阈值需要两个阈值(高阈值和低阈值),阈值设置的太高,会使得真正的边缘点过滤掉;阈值设置的太低,会使得噪音也被认为边缘点。

    a. 如果某一像素位置的幅值超过 阈值, 该像素被保留为边缘像素(强边缘点)。

    b. 如果某一像素位置的幅值小于 阈值, 该像素被排除。

    c. 如果某一像素位置的幅值在两个阈值之间(弱边缘点),该像素仅仅在连接到一个高于 阈值的像素时被保留。

    Canny 推荐的 : 阈值比在 2:1 到3:1之间。

    强边缘点可以认为是真的边缘。弱边缘点则可能是真的边缘,也可能是噪声或颜色变化引起的。为得到精确的结果,后者引起的弱边缘点应该去掉。通常认为真实边缘引起的弱边缘点和强边缘点是连通的,而由噪声引起的弱边缘点则不会。所谓的滞后边界跟踪算法检查一个弱边缘点的8连通领域像素,只要有强边缘点存在,那么这个弱边缘点被认为是真是边缘保留下来。

    Canny 的目标是找到一个最优的边缘检测算法,最优边缘检测的含义是:

    好的检测 - 算法能够尽可能多地标识出图像中的实际边缘。

    好的定位 - 标识出的边缘要尽可能与实际图像中的实际边缘尽可能接近。

    最小响应 - 图像中的边缘只能标识一次,并且可能存在的图像噪声不应标识为边缘。

    较大的阈值2用于检测图像中明显的边缘,但一般情况下检测的效果不会那么完美,边缘检测出来是断断续续的。所以这时候用较小的第一个阈值用于将这些间断的边缘连接起来。

    实现函数: cv2.Canny(image(必须为单通道图), threshold1, threshold2 )

    3. 所有算子的代码实现:

    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    # sobel算子、Laplacian算子、Canny算子、scharr算子、Roberts算子、prewitt算子
    
    # ********************Sobel边缘检测*****************************
    def edge_sobel(src):
        kernelSize = (3, 3)
        gausBlurImg = cv2.GaussianBlur(src, kernelSize, 0)
    
        # 转换为灰度图
        channels = src.shape[2]
        if channels > 1:
            src_gray = cv2.cvtColor(gausBlurImg, cv2.COLOR_RGB2GRAY)
        else:
            src_gray = src.clone()
    
        scale = 1
        delta = 0
        depth = cv2.CV_16S
    
        # 求X方向梯度(创建grad_x, grad_y矩阵)
        grad_x = cv2.Sobel(src_gray, depth, 1, 0)
        abs_grad_x = cv2.convertScaleAbs(grad_x)
    
        # 求Y方向梯度
        grad_y = cv2.Sobel(src_gray, depth, 0, 1)
        abs_grad_y = cv2.convertScaleAbs(grad_y)
    
        # 合并梯度(近似)
        edgeImg = cv2.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0)
        return edgeImg
    
    
    # ********************Laplacian边缘检测*****************************
    def edge_laplacian(src):
        scale = 1
        delta = 0
        depth = cv2.CV_16S
    
        if src.shape[2] > 1:
            src_gray = cv2.cvtColor(src, cv2.COLOR_RGB2GRAY)
        else:
            src_gray = src.clone()
    
        kernelSize = (3, 3)
        gausBlurImg = cv2.GaussianBlur(src_gray, kernelSize, 0)
        laplacianImg = cv2.Laplacian(gausBlurImg, depth, kernelSize)
        edgeImg = cv2.convertScaleAbs(laplacianImg)
        return edgeImg
    
    
    # ********************Canny边缘检测*****************************
    def edge_canny(src, threshold1, threshold2):
        kernelSize = (3, 3)
    
        gausBlurImg = cv2.GaussianBlur(src, kernelSize, 0)
        edgeImg = cv2.Canny(gausBlurImg, threshold1, threshold2)
        return edgeImg
    
    
    # ********************主函数*****************************
    # imgSrc = cv2.imread( "3.jpg", 1)                                  #复杂场景
    imgSrc = cv2.imread("../images/2.png")  # 简单场景
    img = cv2.resize(imgSrc, (0, 0), fx=0.25, fy=0.25, interpolation=cv2.INTER_NEAREST)
    
    sobelImg = edge_sobel(img)
    laplacianImg = edge_laplacian(img)
    cannyImg = edge_canny(img, 20, 60)
    
    # scharr算子
    img1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    scharrx = cv2.Scharr(img1, cv2.CV_64F, 1, 0)
    scharry = cv2.Scharr(img1, cv2.CV_64F, 0, 1)
    scharrx = cv2.convertScaleAbs(scharrx)
    scharry = cv2.convertScaleAbs(scharry)
    scharrxy = cv2.addWeighted(scharrx, 0.5, scharry, 0.5, 0)
    
    # Roberts算子
    grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
    kernely = np.array([[0, -1], [1, 0]], dtype=int)
    x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
    y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
    # 转uint8
    absX = cv2.convertScaleAbs(x)
    absY = cv2.convertScaleAbs(y)
    Roberts = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
    
    # prewitt算子
    kernelx = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]], dtype=int)
    kernely = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=int)
    x = cv2.filter2D(grayImage, cv2.CV_16S, kernelx)
    y = cv2.filter2D(grayImage, cv2.CV_16S, kernely)
    # 转uint8
    absX = cv2.convertScaleAbs(x)
    absY = cv2.convertScaleAbs(y)
    Prewitt = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
    
    # cv2.imshow( "Origin", img )
    # cv2.imshow('scharr', scharrxy)
    # cv2.imshow('Robert', Roberts)
    # cv2.imshow('prewitt', Prewitt)
    # cv2.imshow("sobellaplaciancanny", np.hstack([sobelImg, laplacianImg, cannyImg]))
    # cv2.imshow("scharrxyRobertsPrewitt", np.hstack([scharrxy, Roberts, Prewitt]))
    
    titles = ['sobelImg', 'laplacianImg ', 'cannyImg', 'scharrxy', ' Roberts', 'Prewitt']
    images = [sobelImg, laplacianImg, cannyImg, scharrxy, Roberts, Prewitt]
    
    for i in range(6):
        plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
        plt.title(titles[i])
        plt.xticks([]), plt.yticks([])
    
    plt.show()
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()

     

    展开全文
  • 近年来视频监控已渗透国民生活的各个领域:小区安保监控, 银行自动柜员机监控,交通方面的违章和流量监控等。视频监控可以 有效防止各种刑事案件的发生...我们将相机干扰定义为:相机所拍摄画面要有剧烈的变化
  • 实时采集电机电流数据,利用PLC控制系统将数据传送主控制室监控画面,形成电流曲线,可以实现对电机运行状态的实时监测。分析电流的变化趋势,可以为生产组织管理和设备检修管理提供必要的数据依据。
  • 例五:我的豪杰超级解霸自从上网后就不能播放了,每次都提示“0x060692f6”(每次变化)指令引用的“0xff000011”内存不能为 “read”,终止程序请按确定。解决方法:试试重装豪杰超级解霸,如果重装后还会,官方...
  • 判断是否存在人脸,如果存在人脸则定位人脸的位置 标准的目标检测问题(针对人脸目标) 姿态和表情的变化 不同人的外观差异 光照,遮挡的影响 不同视角 不同大小、位置 人脸标注方法—矩形标注 传统方法都是用一...
  • 跟着敲13.7章 加了stats.game_active后 画面不动 终端显示stats.ships_left值不断减少直到0  <code class="language-python">#alien_invasion.py # coding=gbk import sys import pygame from pygame....
  • 如果系统检测到无效或非标准分区表标记,将提示用户是否继续执行该命令。除非您访问驱动器有问题,否则不要继续进行。向系统分区写入新的主引导记录可能破坏分区表并导致分区无法访问。  format  将指定的驱动器...
  • 固定监控,需要快速标记全天候出现画面变化的时间段,需要使用到运动侦测的方法,本文主要使用帧差法进行计算。 点跟踪: 这类方法通常在连续帧中检测到的目标被表达为点。再引入其它方法来进行目标检测。其问题...
  • 50秒(快速变化)-> 10秒处理,并且很大程度上取决于所获得的视觉效果,因为它跳过了没有发生变化且也没有检测到脸部的大部分画面。 使用考勤系统 使用已安装的软件包将存储库克隆到python虚拟环境中:* face_...
  • 离线人脸识别SDK

    2020-11-08 12:02:01
    其次,通过面部关键点定位技术,以微秒级的速度,完成眼、口、鼻轮廓等面部关键点进行精准定位,且不会受光线变化、表情变化及头发、帽子遮挡等影响; 活体: RGB 单目活体防伪; 识别准确率达 99.9%..
  • 1.判断拍摄画面是否发生变化时,要考虑光线的变化,小动物像虫子等的进入带来的误差,所以我采用了判断前后两张图片的相似度来判断变化。 2.要实现远程连接,必须要经过网络,自己还不具备编写这样软件的能力...
  • wifi天眼 一款智能远程监控软件。

    千次阅读 2014-04-01 21:06:52
    wifi天眼 一款智能远程监控软件。   wifi天眼是一款基于WIFI的监控软件,在WIFI网络的情况下,局域网中的任何设备都能访问手机相机,只...当画面检查视频中存在运动的物体便报警,将视频图片上传网络服务器中。
  • Unity Shader学习记录(十) ...  一个典型的例子是边缘检测,前文中使用Sobel算子进行卷积运算来检测边缘其实并不精确,因为颜色的变化有时候并不说明真正的物体边缘,而且光照效果也会影响边缘检...
  • 转自:https://zhuanlan.zhihu.com/p/28582582在了解什么是双核对焦前,先让我们了解一下反差对焦和相位对焦①反差对焦反差对焦的原理是根据焦点处画面的对比度变化,寻找...此外由于要检测画面对比度的反差,一旦被...
  • 体感互动通过体感设备,来检测人体,通过景物深度处理技术把人物从摄像头捕捉画面中分离出来; 随着手指的挥动、在不接触任何物体的情况下做出手势,根据自己的要求发出一些信号,画面就会做出相应的变化,同时可...
  • 体感互动通常指的是隔空互动,通过体感设备,来检测人体,通过景物深度处理技术把人物从摄像头捕捉画面中分离出来; 随着手指的挥动、在不接触任何物体的情况下做出手势,根据自己的要求发出一些信号,画面就会...
  • E003 予热异常 定影预热完成后,主热敏电阻TH1检测到100度后,又检测到定影温度低于70度达2秒 E004 定影灯SSR短路 电源开关ON后,当定影启动信号(HTRD)为OFF时却检测到SSR导通信号(SSR ON)达3秒,(硬电路检测) E005 定...
  • 人脸业务场景

    2019-04-03 09:50:06
    判断是否存在人脸,如果存在人脸则定位人脸的位置(标准的目标检测问题:针对人脸目标) 姿态和表情的变化 不同人的外观差异 光照,遮挡的影响 不同视角 不同大小,位置 人脸标注方法--矩形标注 传统方法都...
  • 1、电阻检测法,将万用表调电阻档,检测一块正常的电路板的某点的地电阻值,再检测另一块相同的电路板的同一个点测试与正常的电阻值是否有不同,若不同则就确定了问题的范围。 2、电压检测法,将万用表调电压...
  • 局域网监控软件

    2013-07-25 16:19:34
    检测到下载或上传流量超标时发警告并自动切断网络或自动关机; 4.员工屏幕监控,WorkWin监控能捕获员工屏幕并记录。所有员工机屏幕画面全部保存在监控系统的服务器端。只捕获变化画面,捕获画质和捕获周期可调。...
  • 电子摄像系统已广泛应用于军用及民用测绘系统中,但是效果受其载体不同时刻姿态变化或震动的影响。当工作环境比较恶劣,尤其是在航空或野外操作时,支撑摄像机平台的震动会引起图像画面的抖动,令观察者视觉疲劳,...
  • 电子摄像系统已广泛应用于军用及民用测绘系统中,但是效果受其载体不同时刻姿态变化或震动的影响。当工作环境比较恶劣,尤其是在航空或野外操作时,支撑摄像机平台的震动会引起图像画面的抖动,令观察者视觉疲劳,...
  • 电子摄像系统已广泛应用于军用及民用测绘系统中,但是效果受其载体不同时刻姿态变化或震动的影响。当工作环境比较恶劣,尤其是在航空或野外操作时,支撑摄像机平台的震动会引起图像画面的抖动,令观察者视觉疲劳,...
  • (1)在VC中利用OpenCV打开并显示一张图片picture控件上 (2)通过鼠标拖动框选进行截图并保存为文件,同时显示鼠标坐标变化 (3)利用opencv进行canny边缘检测 (4)打开本机usb摄像头并将视频图像显示在picture控件上 (5...
  • 开启此项设置后,保护卡检测到上述情况,会自动为克隆进度创建‘映射进度’,以保留客户端软件环境的变化。 当用户的机房内同时安装计费系统,并且这种计费系统是基于Windows的,那么用户应该关闭此项设置。 ...

空空如也

空空如也

1 2 3 4
收藏数 62
精华内容 24
关键字:

检测到画面变化