libgphoto2 plus2

preview

preview的意思是预览,代码使用一个for循环快速采集100张图片并保存来展示preview的效果。而我希望的preview是将实时采集的图片通过界面的形式显示出来。preview区分一般采集图片的功能,主要是gp_camera_capture_preview()capture_to_file()的区别,前者采集低分辨率的图片,后者采集高分辨率的图片,并且为了支持采集的模式,相机的采集模式也需要进行不同的调整。

preview代码流程
  1. 初始化相机、相机使能;
  2. 调用camera_eosviewfinder()函数,这个函数的功能有待探讨;
  3. 3-6步是循环中实现的:每个循环同样要新建一个相机文件句柄;
  4. 并且每10次循环就自动对焦一次,也就是调用camera_auto_focus()函数;
  5. 然后调用gp_camera_capture_preview的函数进行采集图片;
  6. 将采集到的图片保存起来,并且释放相机文件句柄。
    camera_eosviewfinder()函数实现中调用了一个函数_lookup_widget()函数,这个函数的第二个参数需要根据相机类型进行调整,第二个参数是个字符串,默认输入是“eosviewfinder”,刚开始调用的时候就老返回错误,然后我询问了libgphoto2的作者,作者告诉我可能需要根据相机的种类进行调整,将输入参数从“eosviewfinder”修改为“viewfinder”——感谢作者,请作者收下我的膝盖!
gp_camera_capture_preview()函数

这个函数采集一个预览,这个预览不会保存在相机上,但是会被返回在一个支持的文件里。在作者提供的例程里,就是采集到了一个相机文件句柄中。类似于上述提到的,该函数对于相机的采集模式有要求,如果是一般的关闭闪光灯、微距等的采集一张图片的模式,该函数的调用会出错,具体表现为:相机会执行采集的指令,然后出现generic error,generic error是什么原因导致的以及怎么处理,对于没有明确开发手册说明,所以处理方式并不明确。而我最终解决的方式为:调整了数码相机的采集模式,修改oneshot模式为P,TV,AV等,我试验的P是可以的,支持了该函数的调用,终于将代码跑通,获得了低分辨率的图片。

例程中的代码+一些中文注释
		Camera	*canon;
        int	i, retval;
        GPContext *canoncontext = sample_create_context();

        //gp_log_add_func(GP_LOG_ERROR, errordumper, 0);
        gp_camera_new(&canon);//新建相机对象

        /* When I set GP_LOG_DEBUG instead of GP_LOG_ERROR above, I noticed that the
         * init function seems to traverse the entire filesystem on the camera.  This
         * is partly why it takes so long.
         * (Marcus: the ptp2 driver does this by default currently.)
         */
        printf("Camera init.  Takes about 10 seconds.\n");
        retval = gp_camera_init(canon, canoncontext);//相机初始化
        if (retval != GP_OK) {
            printf("  Retval: %d\n", retval);
            exit (1);
        }
        canon_enable_capture(canon, TRUE, canoncontext);//canon使能
        retval = camera_eosviewfinder(canon,canoncontext,1);//viewfinder,这个功能暂时还不是很清楚
        if (retval != GP_OK) {
            fprintf(stderr,"camera_eosviewfinder(1): %d\n", retval);
            exit(1);
        }
        /*set_capturetarget(canon, canoncontext);*/
        printf("Taking 100 previews and saving them to snapshot-XXX.jpg ...\n");
        for (i=0;i<100;i++) {//循环100次,采集小图片并保存
            CameraFile *file;
            char output_file[32];

            fprintf(stderr,"preview %d\n", i);
            retval = gp_file_new(&file);//新建相机文件句柄
            if (retval != GP_OK) {
                fprintf(stderr,"gp_file_new: %d\n", retval);
                exit(1);
            }

            /* autofocus every 10 shots */
            if (i%10 == 9) {
                camera_auto_focus (canon, canoncontext, 1);
                /* FIXME: wait a bit and/or poll events ? */
                camera_auto_focus (canon, canoncontext, 0);
            } else {
                camera_manual_focus (canon, (i/10-5)/2, canoncontext);
            }
    #if 0 /* testcase for EOS zooming */
            {
                char buf[20];
                if (i<10) set_config_value_string (canon, "eoszoom", "5", canoncontext);
                sprintf(buf,"%d,%d",(i&0x1f)*64,(i>>5)*64);
                fprintf(stderr, "%d - %s\n", i, buf);
                set_config_value_string (canon, "eoszoomposition", buf, canoncontext);
            }
    #endif
            retval = gp_camera_capture_preview(canon, file, canoncontext);//采集小分辨率的图片
            if (retval != GP_OK) {
                fprintf(stderr,"gp_camera_capture_preview(%d): %d\n", i, retval);
                exit(1);
            }
            sprintf(output_file, "snapshot-%03d.jpg", i);
            retval = gp_file_save(file, output_file);//将小分辨率的图片保存到output_file指定的位置
            if (retval != GP_OK) {
                fprintf(stderr,"gp_camera_capture_preview(%d): %d\n", i, retval);
                exit(1);
            }
            gp_file_unref(file);
        /*
            sprintf(output_file, "image-%03d.jpg", i);
                capture_to_file(canon, canoncontext, output_file);
        */
        }
        retval = camera_eosviewfinder(canon,canoncontext,0);
        if (retval != GP_OK) {
            fprintf(stderr,"camera_eosviewfinder(0): %d\n", retval);
            exit(1);
        }
        sleep(10);
        gp_camera_exit(canon, canoncontext);//退出相机

在界面中显示preview的结果

东西怎么折腾也不会坏掉——坏掉老师也不会让赔吧真想手动@包工头
实现思路

  1. 将上述代码中retval = gp_file_save(file, output_file);file中的数据转到熟悉的OpenCV的数据结构Mat中;
  2. 将Mat中的数据通过界面的形式展示出来。
将file中的数据转到Mat中

file是CameraFile指针,该数据结构的内部数据是私有的,所以不能直接访问,我也没兴趣去寻找该数据结构的友元函数了,因此我采取的策略是:依然按照参考代码中存储图片的方式,将图片保存到计算机中指定的位置,然后使用OpenCV的imread()函数读到Mat中——咿呀呀,我真懒。

通过界面展示Mat中的数据

涉及到一些信号槽函数、相机句柄等全局变量,所以讲for循环中的代码放到一个槽函数中,将别的如:相机句柄的定义放到界面类中,相机句柄的初始化,canon相机的使能放到界面的构造函数中,将相机的释放放到界面的析构函数中。然后使用一个计时器timeout函数作为信号以运行槽函数即可。显然这种思路成功实现了数码相机的liveview需求。

preview模式下capture_to_file(memory)可以吗?

在支持preview的P模式下,preview的过程中是可以运行capture_to_file函数的。但是我个人总感觉对相机不太友好。出现了以下几种情况:

  1. preview过程中调用capture_to_file函数,相机反应相对比较慢,采集图片的速度也比较慢;
  2. preview的过程中调用capture_to_file函数,相机不是很稳定,如果随意对相机进行操作,会导致调用capture_to_file函数调用失败,可能是capture_to_file函数有参数保存了相机的工作模式,一旦修改相机的模式,就与之前记录下的模式产生冲突,所以capture_to_file函数运行会失败;但preview没有受到影响;
  3. 相机在程序运行结束后,不会自动退出preview的状态,相机不再受手动操作,启动程序可以被程序接管。——对此我不知道相机发生了什么。

下一步

既然有办法可视化preview了,我就可以尝试在自己的主要界面上集成这个功能了,将双相机系统精简为单相机系统。需要特别注意,如果用不同的线程访问(或计时器触发)相机,该如何避免冲突。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值