camera 订阅
camera,英语单词,名词,意为“照相机;摄影机”。 展开全文
camera,英语单词,名词,意为“照相机;摄影机”。
信息
外文名
camera
词    性
名词
camera单词发音
英[ˈkæmrə]美[ˈkæmrə] [1] 
收起全文
精华内容
参与话题
问答
  • Camera专题】-从零开始的Camera学习之路——启动篇

    千次阅读 热门讨论 2019-01-26 12:08:28
    如今工作也一年多了,在现在的公司是啥都调试,从EMMC,TP,LCD,CAMERA等等,对于底层驱动也有了一定的认识,现在的状态就是啥都会一些,啥都不精通。 于是,寻寻觅觅一年多,终于确定下来职业发展方向-Camera驱动...

    1.吐槽

    如今工作也一年多了,在现在的公司是啥都调试,从EMMC,TP,LCD,CAMERA等等,对于底层驱动也有了一定的认识,现在的状态就是啥都会一些,啥都不精通。
    于是,寻寻觅觅一年多,终于确定下来职业发展方向-Camera驱动开发


    2019.1.26更新吐槽:
    之前在大学开的博客,没能坚持写技术文章,后来工作后开始坚持写技术文档!
    但是觉得csdn在使用MarkDown语法时,上传图片特别麻烦,于是转战简书写了!
    不过现在感觉,还是csdn做技术氛围较强,简书感觉变了!
    现在就同步更新吧!


    一方面,这一块的薪资诱人,
    在这里插入图片描述

    另一方面,比较感兴趣,而且恰好公司有老前辈搞这个,可以少走弯路!
    但是不确定我们这个老前辈什么水平,我能跟他学的东西或许真的不多,主要还是靠自己静下心来自学吧。

    正如乔布斯所说的——stay hungry,stay foolish!要不停地去寻找自己想学习的东西,想从事的工作!!!从来都不晚!

    2.学习

    camera的方向

    • 1.camera 驱动调试(kernel层)——c语言

    • 2.camera hal层调试开发——c++(涉及到JNI)

    • 3.camera效果调试(tuning)——图像原理,光学,c/c++(涉及面广)

    • 4.camera应用层开发——java

    我现在的想法就是未来3-5年,把1-2搞通搞明白!

    camera的学习方法

    如标题所言,既然是从0开始,那么就是老老实实打基础,掌握必备的技能。

    智者千虑必有一失,愚者千虑亦有一得。

    我自诩是个愚人,傻人用傻方法。

    怎么去学习呢?


    1.看学习文档,边看边记录边思考(好记性不如烂笔头)。

    这些文档来源于网上,MTK官方资料,规格书等。

    2.看源码

    Read the fucking soucecode,这个过程必定是艰辛、枯燥、难熬的。我想唯有坚持可破。

    3.跟着项目解决实际问题。

    解决实际问题,把学到的知识学以致用,积累经验!


    Stay hungry,Stay foolish!

    展开全文
  • camera 基本常识

    万次阅读 2016-08-22 14:22:28
    一、Camera 工作原理介绍 1. 结构 . 一般来说,camera 主要是由 lens 和 sensor IC 两部分组成,其中有的 sensor IC 集成 了 DSP,有的没有集成,但也需要外部 DSP 处理。细分的来讲,camera 设备由下边几部 分...
    
    一、Camera 工作原理介绍
    1. 结构 .

    一般来说,camera 主要是由 lens 和 sensor IC 两部分组成,其中有的 sensor IC 集成 了 DSP,有的没有集成,但也需要外部 DSP 处理。细分的来讲,camera 设备由下边几部 分构成:

     1) lens(镜头) 一般 camera 的镜头结构是有几片透镜组成,分有塑胶透镜(Plastic)和玻璃透 镜(Glass) ,通常镜头结构有:1P,2P,1G1P,1G3P,2G2P,4G 等。

     2) sensor(图像传感器) Senor 是一种半导体芯片,有两种类型:CCD 和 CMOS。Sensor 将从 lens 上传导过来的光线转换为电信号, 再通过内部的 AD 转换为数字信号。 由于 Sensor 的每个 pixel 只能感光 R 光或者 B 光或者 G 光, 因此每个像素此时存贮的是单色的, 我们称之为 RAW DATA 数据。 要想将每个像素的 RAW DATA 数据还原成三基色,就需要 ISP 来处理。 

    3)ISP(图像信号处理) 主要完成数字图像的处理工作,把 sensor 采集到的原始数据转换为显示支持 的格式。 

    4)CAMIF(camera 控制器) 芯片上的 camera 接口电路,对设备进行控制,接收 sensor 采集的数据交给 CPU,并送入 LCD 进行显示。


    2. 工作原理 .
    外部光线穿过 lens 后, 经过 color filter 滤波后照射到 Sensor 面上, Sensor 将从 lens 上传导过来的光线转换为电信号,再通过内部的 AD 转换为数字信号。如果 Sensor 没有集 成 DSP,则通过 DVP 的方式传输到 baseband,此时的数据格式是 RAW DATA。如果集成 了 DSP, RAW DATA 数据经过 AWB、 则 color matrix、 lens shading、 gamma、 sharpness、 AE 和 de-noise 处理,后输出 YUV 或者 RGB 格式的数据。
    最后会由 CPU 送到 framebuffer 中进行显示,这样我们就看到 camera 拍摄到的景象 了。

    3. YUV 与 YCbCr .
    YUV 和 RGB 一样,是色彩空间中常用的色彩模型之一,两者可以相互转换。YUV 中 得 Y 表示亮度,U 和 V 表示色度。与 RGB 相比,它的优点在于占用更少的空间。 YCbCr 则是在世界数字组织视频标准研制过程中作为 ITU - R BT601 建议的一部分, 其实是 YUV 经过缩放和偏移的翻版。 其中 Y 与 YUV 中的 Y 含义一致, Cb , Cr 同样都指色 彩, 只是在表示方法上不同而已。在 YUV 家族中, YCbCr 是在计算机系统中应用最多的成 员, 其应用领域很广泛,JPEG、 MPEG 均采用此格式。 一般人们所讲的 YUV 大多是指 YCbCr。 YCbCr 有许多取样格式, 如 4∶4∶4 , 4∶2∶2 , 4∶1∶1 和 4∶2∶0。

    二、Camera 硬件
    1. CAMIF .

    如下是 S5PV210 的 camera 系统的结构图:



    S5PV210 的 camera 接口控制器叫 FIMC4.3,它支持 ITU R BT-601/656、AXI 和 MIPI(CSI)三种接口方式,最大输入像素是 8192*8192。S5PV210 有三组 camera 接口。

    主要特性: 支持多种输入接口类型:



    ITU-R BT 601/656 模式 DMA(AXI 64 位)模式 MIPI(CSI)模式 Direct FIFO 模式 支持多种输出接口:DMA 模式/Direct FIFO 模式 支持数码调焦(DZI) 最大输入像素 8192*8192 支持图像翻转、旋转等处理效果 生成多种图片格式 支持采集帧控制

    2. 接口信号 .

    FIMC 信号定义如下所示(YCbCr 模式)

    Signal

    VSYNC HREF PCLK DATA[7:0] FIELD CAM_MCLK I I I I


    I/O
    帧同步信号 行同步信号 像素时钟 像素数据 FIELD 信号

    Description

    Type

    Muxed

    O O

    系统时钟信号



    通过 CAM_MCLK 给摄像头提供时钟,RST 是复位线,PWDN 在摄像头工作时应该始终 为低。HREF 是行参考信号,PCLK 是像素时钟,VSYNC 是场同步信号。一旦给摄像头提供了 时钟,并且复位摄像头,摄像头就开始工作了,通过 HREF,PCLK 和 VSYNC 同步传输数字图 像信号。数据是通过 DATA0~DATA7 这八根数据线并行送出的。

    3. 工作时序 .
    FIMC43 支持如下两种视频数据:

    ITU-R BT 601 输入时序图 这种方式下行和帧同步信号独立于视频数据,因此需要同步信号。



    ITU-R BT 656 输入时序图



    这种方式下同步信号已经内嵌到视频数据中了,因此不需要额外的行和帧同步信号。

    (ITU-R BT 601: 16 位数据传输;21 芯;Y、U、V 信号同时传输。 ITU-R BT 656: 9 芯,不需要同步信号;8 位数据传输;串行视频传输;传输速率是 601 的 2 倍;先传 Y, 后传 UV。 )

    同步信号的时延参数 t1:表示 VSYNC 前、后插入周期 t2:表示 HREF 前插入周期 t3:表示 HREF 宽度 t4:表示 HREF 后插入周期



    4. 外部接口 . 外部接口
    硬件原理图的 CAM A 部分:

    CAM B 部分

    5. Camera 内部结构图 .
    下图是 camera 内部结构框图,以 OV sensor 为例:

    三、Camera 驱动
    1. V4L2 .

    1)简介 ) 在 Linux 中,摄像头方面的标准化程度比较高,这个标准就是 V4L2 驱动程序,这也是 业界比较公认的方式。 V4L 全称是 Video for Linux,是 Linux 内核中标准的关于视频驱动程序,目前使用比 较多的版本是 Video for Linux 2, 简称 V4L2。 它为 Linux 下的视频驱动提供了统一的接口, 使得应用程序可以使用统一的 API 操作不同的视频设备。从内核空间到用户空间,主要的 数据流和控制类均由 V4L2 驱动程序的框架来定义。 V4L2 驱动程序一般只提供 Video 数据的获得,而如何实现视频预览,如何向上层发送 数据,如何把纯视频流和取景器、视频录制等实际业务组织起来,都是 camera 的硬件抽象 层需要负责的工作。

     V4L2 驱动核心实现为如下文件:drivers/media/video/v4l2-dev.c。 V4l2-dev.h 中定义的 video_device 是 V4L2 驱动程序的核心数据结构,它为具体的摄 像头 sensor 驱动提供了接口调用。 V4l2 的采集过程(应用程序):

    1)打开设备,获得文件描述符; 

    2) 设置图片格式;

    3) 分配缓冲区;

    4)启动采集过程,读取数据;

    5) 停止采集,关闭设备。


    2)数据结构 )

     V4L2 的主要数据结构是 video_device,定义在 v4l2_dev.h 中:

    struct video_device { 

    /* device ops */ 

    const struct v4l2_file_operations *fops; /*接口函数指针*/


    /* sysfs */

     struct device dev; struct cdev *cdev; /* v4l 设备结构 */ 

    /* 字符设备结构*/


    /* Set either parent or v4l2_dev if your driver uses v4l2_device */ 

    struct device *parent; struct v4l2_device *v4l2_dev; /* 设备父指针 */

    /* v4l2 设备指针*/


    /* device info */ 

    char name[32]; 

    int vfl_type; /* 'minor' is set to -1 if the registration failed */ 

    int minor; u16 num; /* use bitops to set/clear/test flags */ 

    unsigned long flags; /* attribute to differentiate multiple indices on one physical device */ 

    int index; /*次设备号*/ 

    /*设备名称*/


    /* V4L2 file handles */ 

    spinlock_t fh_lock; /* Lock for all v4l2_fhs */


    struct list_head fh_list; /* List of struct v4l2_fh */

    int debug;

    /* debug 级别*/

    /* Video 标准变量 */ 

    v4l2_std_id tvnorms; /* Supported tv norms */


    v4l2_std_id current_norm; /* Current tvnorm */

    /* 回调函数 */ 

    void (*release)(struct video_device *vdev);


    /* ioctl 回调函数 */ 

    const struct v4l2_ioctl_ops *ioctl_ops; 

    };


    主要接口函数有: int video_register_device(struct video_device *vdev, int type, int nr);

    static int v4l2_ioctl(struct inode *inode, struct file *filp, long arg);

    unsigned int cmd, unsigned

    2. FIMC
    1)简介 ) FIMC 这个模块不仅仅是一个摄像头的控制接口,它还承担着 V4L2 的 output 功能和 overlay 的功能。 FIMC 的驱动在内核中的位置:drivers/media/video/samsung/fimc 它包含下边的文件:
    fimc_regs.c fimc_capture.c fimc_dev.c fimc_output.c fimc_overlay.c fimc_v4l2.c

    它们的组织关系如下:

    可以看到,FIMC 的驱动实现了 v4l2 所有的接口,可以分为 v4l2-input 设备接口, v4l2-output 设备接口以及 v4l2-overlay 设备接口。这里我们主要关注 v4l2-input 设备接口, 因为摄像头属于视频输入设备。 fimc_v4l2.c 里面注册了很多的回调函数,都是用于实现 v4l2 的标准接口的,但是这些 回调函数基本上都不是在 fimc_v4l2.c 里面实现的,而是有相应的.c 分别去实现。比如:

    v4l2-input 设备的操作实现: fimc_capture.c v4l2-output 

    设备的操作实现: fimc_output.c v4l2-overlay 

    设备的操作实现: fimc_overlay.c


    这些代码其实都是和具体硬件操作无关的, 这个驱动把所有操作硬件寄存器的代码都写 到一个文件里面了,就是 fimc40_regs.c。这样把硬件相关的代码和硬件无关的代码分开来 实现是非常好的方式,可以最大限度的实现代码复用。

     2) 数据结构 ) FIMC 的主要数据结构 fimc_control,定义在 fimc.h 中:


    struct fimc_control {
            int                             id;             /* controller id */
            char                            name[16];
            atomic_t                        in_use;
            void __iomem                    *regs;          /* register i/o */
            struct clk                      *clk;           /* interface clock */
            struct regulator        *regulator;             /* pd regulator */
            struct fimc_meminfo             mem;            /* for reserved mem */


            /* kernel helpers */
            struct mutex                    lock;           /* controller lock */
            struct mutex                    alloc_lock;
            struct mutex                    v4l2_lock;
            wait_queue_head_t               wq;
            struct device                   *dev;
            int                             irq;


            /* v4l2 related */
            struct video_device             *vd;
            struct v4l2_device              v4l2_dev;


            /* fimc specific */
            struct fimc_limit               *limit;         /* H/W limitation */
            struct s3c_platform_camera      *cam;           /* activated camera */
            struct fimc_capinfo             *cap;           /* capture dev info */
            struct fimc_outinfo             *out;           /* output dev info */
            struct fimc_fbinfo              fb;             /* fimd info */
            struct fimc_scaler              sc;             /* scaler info */
            struct fimc_effect              fe;             /* fimc effect info */


            enum fimc_status                status;
            enum fimc_log                   log;


            u32                             ctx_busy[FIMC_MAX_CTXS];
    };


    因为 FIMC 一共有三套一样的控制器(fimc0, fimc1, fimc2) ,所以驱动里使用了一个数组来描述:: 

    struct video_device fimc_video_device[FIMC_DEVICES] = { 

    [0] = { .fops = &fimc_fops, .ioctl_ops = &fimc_v4l2_ops, .release = fimc_vdev_release, }, 

    [1] = { .fops = &fimc_fops, .ioctl_ops = &fimc_v4l2_ops, .release = fimc_vdev_release, }, 

    [2] = { .fops = &fimc_fops, .ioctl_ops = &fimc_v4l2_ops, .release = fimc_vdev_release, }, 

    };


    fb_ops 结构体是针对 v4l2 设备的基本操作,定义如下:

    static const struct v4l2_file_operations fimc_fops = { 

                .owner  = THIS_MODULE,

                 .open = fimc_open, 

                 .release  = fimc_release,

                 .ioctl = video_ioctl2,

                 .read = fimc_read,

                 .write = fimc_write,

                 .mmap = fimc_mmap,

                 .poll = fimc_poll,

    }; 

    3)FIMC 初始设置 

    ) 在 S5PV210 中, FIMC 初始设置代码在 /drivers/ arch/arm/mach-s5pv210/mach-t34h.c 中:

    static struct s3c_platform_fimc fimc_plat_lsi = {
            .srclk_name     = "mout_mpll",
            .clk_name       = "sclk_fimc",
            .lclk_name      = "sclk_fimc_lclk",
            .clk_rate       = 166750000,
    #if defined(CONFIG_VIDEO_S5K4EA)
            .default_cam    = CAMERA_CSI_C,
    #else
    #ifdef CAM_ITU_CH_A
            .default_cam    = CAMERA_PAR_A,
    #else
            .default_cam    = CAMERA_PAR_B,
    #endif
    #endif
            .camera         = {
    #ifdef CONFIG_VIDEO_S5K4ECGX
                            &s5k4ecgx,
    #endif
    #ifdef CONFIG_VIDEO_S5KA3DFX
                            &s5ka3dfx,
    #endif
    #ifdef CONFIG_VIDEO_S5K4BA
                            &s5k4ba,
    #endif
    #ifdef CONFIG_VIDEO_S5K4EA
                            &s5k4ea,
    #endif
    #ifdef CONFIG_VIDEO_HM2055
                            &hm2055,
    #endif
    #ifdef CONFIG_VIDEO_GC0308
                            &gc0308,
    #endif
    #ifdef CONFIG_VIDEO_HIMAX2055
                            &himax2055,
    #endif
    #ifdef CONFIG_VIDEO_ADV7181
                            &adv7181,
    #endif
            },
            .hw_ver         = 0x43,
    };



    对于 GPIO 的配置代码在 /drivers/ arch/arm/mach-s5pv210/setup-fimc0.c 中:

    void s3c_fimc0_cfg_gpio(struct platform_device *pdev) { 

    int i = 0;


    /* CAM A port(b0010) : PCLK, VSYNC, HREF, DATA[0-4] */ 

    for (i = 0; i < 8; i++) { 

    s3c_gpio_cfgpin(S5PV210_GPE0(i), S3C_GPIO_SFN(2)); 

    s3c_gpio_setpull(S5PV210_GPE0(i), S3C_GPIO_PULL_NONE);

     } 

    /* CAM A port(b0010) : DATA[5-7], CLKOUT(MIPI CAM also), FIELD */ 


    for (i = 0; i < 5; i++) { 

    s3c_gpio_cfgpin(S5PV210_GPE1(i), S3C_GPIO_SFN(2)); 

    s3c_gpio_setpull(S5PV210_GPE1(i), S3C_GPIO_PULL_NONE); 

    } /* CAM B port(b0011) : DATA[0-7] */ 


    for (i = 0; i < 8; i++) { 

    s3c_gpio_cfgpin(S5PV210_GPJ0(i), S3C_GPIO_SFN(3));

     s3c_gpio_setpull(S5PV210_GPJ0(i), S3C_GPIO_PULL_NONE); 

    } /* CAM B port(b0011) : PCLK, VSYNC, HREF, FIELD, CLCKOUT */ 


    for (i = 0; i < 5; i++) { 

    s3c_gpio_cfgpin(S5PV210_GPJ1(i), S3C_GPIO_SFN(3)); 

    s3c_gpio_setpull(S5PV210_GPJ1(i), S3C_GPIO_PULL_NONE); 

    }


    4)接口函数 ) 

    FIMC 的主要回调函数如下,实现在 fimc_v4l2.c 中:


    const struct v4l2_ioctl_ops fimc_v4l2_ops = {
            .vidioc_querycap                = fimc_querycap,
            .vidioc_reqbufs                 = fimc_reqbufs,
            .vidioc_querybuf                = fimc_querybuf,
            .vidioc_g_ctrl                  = fimc_g_ctrl,
            .vidioc_s_ctrl                  = fimc_s_ctrl,
            .vidioc_s_ext_ctrls             = fimc_s_ext_ctrls,
            .vidioc_cropcap                 = fimc_cropcap,
            .vidioc_g_crop                  = fimc_g_crop,
            .vidioc_s_crop                  = fimc_s_crop,
            .vidioc_streamon                = fimc_streamon,
            .vidioc_streamoff               = fimc_streamoff,
            .vidioc_qbuf                    = fimc_qbuf,
            .vidioc_dqbuf                   = fimc_dqbuf,
            .vidioc_enum_fmt_vid_cap        = fimc_enum_fmt_vid_capture,
            .vidioc_g_fmt_vid_cap           = fimc_g_fmt_vid_capture,
            .vidioc_s_fmt_vid_cap           = fimc_s_fmt_vid_capture,
            .vidioc_try_fmt_vid_cap         = fimc_try_fmt_vid_capture,
            .vidioc_enum_input              = fimc_enum_input,
            .vidioc_g_input                 = fimc_g_input,
            .vidioc_s_input                 = fimc_s_input,
            .vidioc_g_parm                  = fimc_g_parm,
            .vidioc_s_parm                  = fimc_s_parm,
            .vidioc_queryctrl               = fimc_queryctrl,
            .vidioc_querymenu               = fimc_querymenu,
            .vidioc_g_fmt_vid_out           = fimc_g_fmt_vid_out,
            .vidioc_s_fmt_vid_out           = fimc_s_fmt_vid_out,
            .vidioc_try_fmt_vid_out         = fimc_try_fmt_vid_out,
            .vidioc_g_fbuf                  = fimc_g_fbuf,
            .vidioc_s_fbuf                  = fimc_s_fbuf,
            .vidioc_try_fmt_vid_overlay     = fimc_try_fmt_overlay,
            .vidioc_g_fmt_vid_overlay       = fimc_g_fmt_vid_overlay,
            .vidioc_s_fmt_vid_overlay       = fimc_s_fmt_vid_overlay,
    };
                                                                  


    5)寄存器操作(fimc_regs.c) )寄存器操作( )

    对于寄存器的操作,实现都在 fimc_regs.c 文件中,如

    int fimc_hwset_camera_source(struct fimc_control *ctrl) {


     struct s3c_platform_camera *cam = ctrl->cam; u32 cfg = 0;


    cfg |= S3C_CISRCFMT_ITU601_8BIT; cfg |= cam->order422;

    if (cam->type == CAM_TYPE_ITU)

    cfg |= cam->fmt;

    cfg |= S3C_CISRCFMT_SOURCEHSIZE(cam->width); 

    cfg |= S3C_CISRCFMT_SOURCEVSIZE(cam->height);


    writel(cfg, ctrl->regs + S3C_CISRCFMT);

    return 0; 

    }


    int fimc_hwset_enable_irq(struct fimc_control *ctrl, int overflow, int level) { 

    u32 cfg = readl(ctrl->regs + S3C_CIGCTRL);


    cfg &= ~(S3C_CIGCTRL_IRQ_OVFEN | S3C_CIGCTRL_IRQ_LEVEL); 

    cfg |= S3C_CIGCTRL_IRQ_ENABLE;


    if (overflow) cfg |= S3C_CIGCTRL_IRQ_OVFEN;

    if (level) cfg |= S3C_CIGCTRL_IRQ_LEVEL;

    writel(cfg, ctrl->regs + S3C_CIGCTRL);

    return 0; 

    }


    3. Sensor 驱动

    1)简介, 

    )简介 本方案中使用了两个摄像头模组: MT9P111 和 S5K6AAFX。 其中 MT9P111 是 APTINA 公司推出的 1/4 英寸光学格式 5M 单芯片传感器,用作后摄像头;S5K6AAFX 是三星出的 1.3M CMOS 高清图像传感器,用作前摄像头。 

    2)参数设置 

    )参数设置 MT9P111 的参数设置

    #ifdef MT9P111_ENABLED 

    static struct mt9p111_platform_data mt9p111_plat = { 

    .default_width = 1024, 

    .default_height = 600, 

    .pixelformat = V4L2_PIX_FMT_UYVY, 

    .freq = 24000000, 

    .is_mipi = 0, 

    }; 


    static struct i2c_board_info mt9p111_i2c_info = { 

    I2C_BOARD_INFO("MT9P111", 0x3D),//0x7a,0x7b .

    platform_data = &mt9p111_plat, 

    }; 


    static struct s3c_platform_camera mt9p111 = { 

    .id = CAMERA_PAR_A,

    .type= CAM_TYPE_ITU,

    .fmt =  = ITU_601_YCBCR422_8BIT,


    .order422 = CAM_ORDER422_8BIT_CBYCRY, 

    .i2c_busnum 

    .info = 7,


    = &mt9p111_i2c_info, = V4L2_PIX_FMT_UYVY, = "xusbxti",

    .pixelformat .srclk_name

    .clk_name = "sclk_cam0",

    .clk_rate = 24000000,

    .line_length 

    .width 

    .height

    .window 

    .left = 0, 

    .top = 0, 

    .width 

    .height 

    }, = 1024, = 600, = 1920, = 1024, = 600, ={


    /* Polarity */ .inv_pclk = 0, .inv_vsync .inv_href = 0, .inv_hsync = 0, = 0,

    .initialized = 0, .cam_power }; #endif = smdkv210_cam0_power,

    S5K6AAFX 的参数设置

    #ifdef S5K6AAFX_ENABLED 

    static struct s5k6aafx_platform_data s5k6aafx_plat = { 

    .default_width = 800, 

    .default_height = 600,

     .pixelformat = V4L2_PIX_FMT_YUYV, 

    .freq = 24000000,


    .is_mipi = 0, 

    }; 

    static struct i2c_board_info s5k6aafx_i2c_info = {


    I2C_BOARD_INFO("s5k6aafx", 0x3c), 

    .platform_data = &s5k6aafx_plat,

     }; 


    static struct s3c_platform_camera s5k6aafx = { 

    .id 

    .type 

    .fmt = CAMERA_PAR_B, = CAM_TYPE_ITU, = ITU_601_YCBCR422_8BIT,


    .order422 = CAM_ORDER422_8BIT_YCBYCR, .i2c_busnum .info = 4,

    = &s5k6aafx_i2c_info, = V4L2_PIX_FMT_YUYV, = "xusbxti",

    .pixelformat .srclk_name

    .clk_name = "sclk_cam1", .clk_rate = 24000000, .line_length = 1280,

    /* default resol for preview kind of thing */ 

    .width .height 

    .window .left = 0, 

    .top = 0, .width 

    .height }, /* Polarity */

     .inv_pclk = 0, 

    .inv_vsync = 0, = 800, = 600, = 800, = 600, ={


    .inv_href = 0, 

    .inv_hsync = 0,


    .initialized = 0, 

    .cam_power }; 

    #endif = smdkv210_cam1_power,


    3)数据结构 )

    (未注释)

    struct v4l2_subdev { 

    struct list_head list; 

    struct module *owner; 

    u32 flags; 

    struct v4l2_device *v4l2_dev; 

    const struct v4l2_subdev_ops *ops; /* name must be unique */ 

    char name[V4L2_SUBDEV_NAME_SIZE]; /* can be used to group similar subdevs, value is driver-specific */ 

    u32 grp_id; /* pointer to private data */ 

    void *priv;

     }; 

    #endif


    4)接口函数 )

    (未注释)

    static const struct v4l2_subdev_core_ops mt9p111_core_ops = { 

    .init = mt9p111_init, /* initializing API */


    .s_config = mt9p111_s_config, /* Fetch platform data */ 

    .queryctrl = mt9p111_queryctrl, 

    .querymenu = mt9p111_querymenu,

     .g_ctrl = mt9p111_g_ctrl, 

    .s_ctrl = mt9p111_s_ctrl,

     };


    static const struct v4l2_subdev_video_ops mt9p111_video_ops = { 

    // .s_crystal_freq = mt9p111_s_crystal_freq, 

    .g_fmt = mt9p111_g_fmt, 

    .s_fmt = mt9p111_s_fmt,

     .enum_framesizes = mt9p111_enum_framesizes, // //

     .enum_frameintervals = mt9p111_enum_frameintervals, 

    .enum_fmt = mt9p111_enum_fmt, 

    .try_fmt = mt9p111_try_fmt, 

    .g_parm = mt9p111_g_parm, 

    .s_parm = mt9p111_s_parm, 

    .s_stream = mt9p111_s_stream, };


    static const struct v4l2_subdev_ops mt9p111_ops = { 

    .core = &mt9p111_core_ops, 

    .video = &mt9p111_video_ops, 

    };

     #endif

    展开全文
  • Camera tuning 基础知识点

    千次阅读 2018-03-09 15:15:40
    相关知识点总结:一、模组及工艺相关知识 ①模组的组成 1)模组的基本组成。(AF&amp;FF) 2)镜头----镜头的发展历史,镜头相关参数解析,镜头的选型依据,优劣判断。(MTF,DOF,Focus,AF,P&...
    相关知识点总结:
    一、模组及工艺相关知识
         ①模组的组成
              1)模组的基本组成。(AF&FF)
              2)镜头----镜头的发展历史,镜头相关参数解析,镜头的选型依据,优劣判断。(MTF,DOF,Focus,AF,P&G....)
              3)sensor----sensor的发展历史,技术演进,sensor本身特性参数解析,主流sensor厂工艺技术解析,分析各大sensor厂之间的差异,优缺点,同时能从某几颗sensor来分析。(了解带有PD的sensor)
                        1’sensor硬件电路设计部分要了解。
                        2’驱动相关部分,MIPI时序,sensor hts,vts,pclk,等的配置要了解。
              4)AF driver 了解,如何控制driver ic,如何设置dumping,ring时间等。
              5)了解模组硬件layout,走线,电子元器件,连机器等设计缺陷对于图像质量的影响。
         ②模组的组装工艺,优劣。了解模组设计上的其他工艺,OIS等。
         ③了解模组厂是如何测试最终的模组是否满足需要,测试方法,测试标准。
         ④学习模组厂对于模组差异性的控制,golden,limit,normal选择依据,otp写入参数等。
         ⑤综合考虑模组选型参考依据,以及模组最终确定选型之后,所能成像的影响质量和其他模组的对比。
    二、图像及色彩处理基本理论和算法
         ①色彩的基本理论。
         ②ISP流程分析。
         ③3A的基本算法原理。

         ④ISP各模块分模块讲解算法模型等。(CCM,去噪,锐化等)。

    三、图像质量评价方法,主客观测试方法
         ①客观测试方法
              基本测试标准,及测试方法,(imatest,DXO等主流厂商的测试方法)
         ②主观测试方法
              主观测试场景,以及对于测试场景的分析方法。
         ③综合从哪些参数评价图像质量。了解客户的关注点。

    以上为自己简单总结的知识点,欢迎大神吐槽。

    展开全文
  • Android Camera基本用法一

    万次阅读 2019-01-17 18:59:49
    1 Camera 简介 讲解编解码之前先对Camera进行简单的介绍,本篇介绍完之后只能保证小白会用Camera预览画面,其他的Camera知识会后续讲解。 考虑兼容性依然介绍Camera,目录为android.hardware.Camera,可以看到从...

    1 Camera 简介

    讲解编解码之前先对Camera进行简单的介绍,本篇介绍完之后只能保证小白会用Camera预览画面,其他的Camera知识会后续讲解。
    在这里插入图片描述
    考虑兼容性依然介绍Camera,目录为android.hardware.Camera,可以看到从api21开始这个类已经被标记为过时,谷歌大大推荐使用android.hardware.Camera2,但是Camera2要从api21才支持,但现在大部分开发还必须以4.+为基础进行开发,所以也只能不听google的坚持使用Camera了。

    借助Camera可以利用设备的相机来预览画面,拍照和拍视频。要使用Camera需要在Manifest文件中添加Manifest.permission.CAMERA 权限同时如果要进行自动对焦,还需要特性声明。
    完整地权限和特性声明设置为:

     <uses-permission android:name="android.permission.CAMERA" />
     <uses-feature android:name="android.hardware.camera" />
     <uses-feature android:name="android.hardware.camera.autofocus" />
    //存储权限也需要
    <uses-permission android:name="android.permission.WEITE_EXTERNAL_STORAGE" />
    

    注意:如果你只是想简单的实现拍照和拍照视频功能,可以利用Intent打开系统提供的功能。MediaStore.ACTION_IMAGE_CAPTURE 拍摄照片;MediaStore.ACTION_VIDEO_CAPTURE 拍摄视频;

    利用Camera想要拍照,需要如下使用步骤:

    • 1 利用open(int)获取Camera实例
    • 2 利用getParameters()获取默认设置,如果需要利用setParameters(Camera.Parameters)进行参数设置
    • 3 利用setDisplayOrientation(int)函数设置正确的预览方向
    • 4 想要预览,需要配合SurfaceView,利用setPreviewDisplay(SurfaceHolder)设置SurfaceView的SurfaceHolder用于预览。
    • 5 调用startPreview()开始预览,拍照之前必须已经开始预览
    • 6 takePicture 拍摄照片
    • 7 调用takePickture后预览会停止,想要继续预览需要调用startPreview()函数
    • 8 调用stopPreview()停止预览
    • 9 调用release()释放资源,为了节省资源在Activity.onPause是调用停止预览,在onResume是开始预览。

    2 打开相机

    检查是否有相机
    /** Check if this device has a camera */
    private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
    // this device has a camera
    return true;
    } else {
    // no camera on this device
    return false;
    }
    }

    获取相机数目:
    Camera.getNumberOfCameras()

    open或open(int)打开相机
    open开启默认相机(后置相机),open(int)开启特定相机,打开相机是可能失败的,所以一定要检查相机是否打开成功,判断Camera是否为null, mCamera = Camera.open(cameraID);
    后置相机和前置相机id常量:CameraInfo.CAMERA_FACING_BACK, CameraInfo.CAMERA_FACING_FRONT
    打开特定相机Camera.open(cameraid)。

    Camera.getCameraInfo() 可以获取CameraInfo,可以知道相机是位于前面还是后面。

    public static class CameraInfo {
            public static final int CAMERA_FACING_BACK = 0;
    
            public static final int CAMERA_FACING_FRONT = 1;
    
            /**
             * 这个值就是标明相机是前置还是后置
             * CAMERA_FACING_BACK or CAMERA_FACING_FRONT.
             */
            public int facing;
    
            public int orientation;
        };
    

    3 相机预览方向设置

    相机的方向(0,90,180,270)有四种,预览需要设置正确的方向和尺寸,预览的图片才不会变形,可以利用Camera.setDisplayOrientaion(int)设置相机的预览方向。可设置的参数有0,90,180,270,默认为0,是指手机的左侧为摄像头顶部画面,所以相机默认为横屏,如果要竖屏预览,就需要设置90度。
    如果想让相机跟随设备方向变化,改变预览的方向,需要结合相机已经旋转的角度和屏幕旋转的角度以及相机的前后(前置相机和后置相机预览界面是不同的,前置有镜面效果),最好固定Activity的方向。
    特别注意:
    设置预览角度,setDisplayOrientation本身只能改变预览的角度previewFrameCallback以及拍摄出来的照片是不会发生改变的,拍摄出来的照片角度依旧不正常的,所以拍摄最后得到的照片需要自行处理(旋转)。
    在布局发生改变时要重新设置相机预览方向。

    一般设置相机方向的通用方法:

    public static int calculateCameraPreviewOrientation(Activity activity) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(mCameraID, info);
        int rotation = activity.getWindowManager().getDefaultDisplay()
                .getRotation();
        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            case Surface.ROTATION_180:
                degrees = 180;
                break;
            case Surface.ROTATION_270:
                degrees = 270;
                break;
        }
    
        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;
        } else {
            result = (info.orientation - degrees + 360) % 360;
        }
        return result;
    }
    

    最终算出来的值result是0,90,180,270中的一个,要获取info.orientation的目的是不知道相机默认角度是多少。

    4 设置预览大小

    相机的宽度和高度跟屏幕坐标不一样,相机的宽高和手机屏幕的宽高是反过来的。例如如果设置展示预览图的SurfaceView的宽高比3:4,选取Camera预览图的尺寸时应该是4:3(因为预览默认对应横向,如果要竖向显示时,就是反过来的。)。

    设备上的相机支持的预览大小是确定的,当然也不是只有一种,会有很多种,我们只能从它支持的大小的列表中选取一个最接近我们需要比例的宽高。

    为了保证相机预览画面不变形,预览界面大小的设置必须和选取的相机支持的尺寸的宽高的比例相同。
    举个例子,获取手机上支持的所有预览尺寸:

    Camera.Parameters parameters = camera.getParameters();
    parameters.getSupportedPreviewSizes()
    

    结果:
    ==支持的预览尺寸=宽= 176 144
    ==支持的预览尺寸=宽= 320 240
    ==支持的预览尺寸=宽= 352 288
    ==支持的预览尺寸=宽= 640 480
    ==支持的预览尺寸=宽= 1280 720
    ==支持的预览尺寸=宽= 1280 960
    ==支持的预览尺寸=宽= 176 144
    ==支持的预览尺寸=宽= 320 240
    ==支持的预览尺寸=宽= 352 288
    ==支持的预览尺寸=宽= 640 480
    ==支持的预览尺寸=宽= 1280 720
    ==支持的预览尺寸=宽= 1280 960

    再次强调:可以看到getSupportedPreviewSizes获取了相机支持的所有预览尺寸,注意一点,屏幕的宽高是按照竖屏获取的,而getSupportedPreviewSizes获得支持的尺寸是按照横屏来说的,也就是说我们上面获取的宽高实际上是反过来的,高是宽,宽是高,不知道大家理解没。

    例如选取上面获取到的640:480,其实对应到竖向屏幕上是480:640。,如果我们选取640x480的尺寸,那么预览Camera的SurfaceView的宽高比也必须为3:4,这样预览的画面才不会变形,否则可能导致变形。
    expectWidth和expectHeight 分别对应期望的宽和高,是对应相机的宽高,所以如果希望在view中看到的是640*480的预览,则期望宽高应该写入3:4的宽高,也就是把希望的对应view的宽高反过来。

    查找最合适尺寸的规则:
    找出最合适的尺寸,规则如下:
    1.将尺寸按比例分组,找出比例最接近屏幕比例的尺寸组
    2.在比例最接近的尺寸组中找出最接近屏幕尺寸且大于屏幕尺寸的尺寸
    3.如果没有找到,则忽略2中第二个条件再找一遍,应该是最合适的尺寸了

    /**
     * 找出最合适的尺寸,规则如下:
     * 1.将尺寸按比例分组,找出比例最接近屏幕比例的尺寸组
     * 2.在比例最接近的尺寸组中找出最接近屏幕尺寸且大于屏幕尺寸的尺寸
     * 3.如果没有找到,则忽略2中第二个条件再找一遍,应该是最合适的尺寸了
     */
    private static Camera.Size findProperSize(Point surfaceSize, List<Camera.Size> sizeList) {
        if (surfaceSize.x <= 0 || surfaceSize.y <= 0 || sizeList == null) {
            return null;
        }
    
        int surfaceWidth = surfaceSize.x;
        int surfaceHeight = surfaceSize.y;
    
        List<List<Camera.Size>> ratioListList = new ArrayList<>();
        for (Camera.Size size : sizeList) {
            addRatioList(ratioListList, size);
        }
    
        final float surfaceRatio = (float) surfaceWidth / surfaceHeight;
        List<Camera.Size> bestRatioList = null;
        float ratioDiff = Float.MAX_VALUE;
        for (List<Camera.Size> ratioList : ratioListList) {
            float ratio = (float) ratioList.get(0).width / ratioList.get(0).height;
            float newRatioDiff = Math.abs(ratio - surfaceRatio);
            if (newRatioDiff < ratioDiff) {
                bestRatioList = ratioList;
                ratioDiff = newRatioDiff;
            }
        }
    
        Camera.Size bestSize = null;
        int diff = Integer.MAX_VALUE;
        assert bestRatioList != null;
        for (Camera.Size size : bestRatioList) {
            int newDiff = Math.abs(size.width - surfaceWidth) + Math.abs(size.height - surfaceHeight);
            if (size.height >= surfaceHeight && newDiff < diff) {
                bestSize = size;
                diff = newDiff;
            }
        }
    
        if (bestSize != null) {
            return bestSize;
        }
    
        diff = Integer.MAX_VALUE;
        for (Camera.Size size : bestRatioList) {
            int newDiff = Math.abs(size.width - surfaceWidth) + Math.abs(size.height - surfaceHeight);
            if (newDiff < diff) {
                bestSize = size;
                diff = newDiff;
            }
        }
    
        return bestSize;
    }
    
    private static void addRatioList(List<List<Camera.Size>> ratioListList, Camera.Size size) {
        float ratio = (float) size.width / size.height;
        for (List<Camera.Size> ratioList : ratioListList) {
            float mine = (float) ratioList.get(0).width / ratioList.get(0).height;
            if (ratio == mine) {
                ratioList.add(size);
                return;
            }
        }
    
        List<Camera.Size> ratioList = new ArrayList<>();
        ratioList.add(size);
        ratioListList.add(ratioList);
    }
    

    设置SurfaceView的宽高为3:4的图像。
    在这里插入图片描述
    设置SurfaceView的宽高为4:3的图像,明显变形了。
    在这里插入图片描述

    5 设置拍摄图片大小

    调用camera的takePicture方法后,获得拍照的图像数据,如何设置保存图片的大小,类似设置预览大小,利用parameters.getSupportedPictureSizes()可以获取支持的保存图片的大小,图片尺寸同样只能从支持的列表中选取一个设置。

    picturesize和previewsize的宽高比也要保证一致,否则获取的图片会将preview时的图像裁剪成picturesize的比例。
    previewsize的分辨率,只会影响预览时的分辨率,不会影响获取图片的分辨率,所以preview只是确定了图像的取景最大范围(所谓的取景范围就是展示多大的画面),最终图片的分辨率是由picturesize来决定。

    6 Camera设置帧率

     /**
         * 选择合适的FPS
         * @param parameters
         * @param expectedThoudandFps 期望的FPS
         * @return
         */
        public static int chooseFixedPreviewFps(Camera.Parameters parameters, int expectedThoudandFps) {
            List<int[]> supportedFps = parameters.getSupportedPreviewFpsRange();
            for (int[] entry : supportedFps) {
                if (entry[0] == entry[1] && entry[0] == expectedThoudandFps) {
                    parameters.setPreviewFpsRange(entry[0], entry[1]);
                    return entry[0];
                }
            }
            int[] temp = new int[2];
            int guess;
            parameters.getPreviewFpsRange(temp);
            if (temp[0] == temp[1]) {
                guess = temp[0];
            } else {
                guess = temp[1] / 2;
            }
            return guess;
        }
    

    getSupportedPreviewFpsRange函数可以获取设备支持的帧率,fps不是越高越好,FPS不宜过高,一般30fps足够了。

    7 如何读取Camera的NV21数据和YUV数据

    给camera对象设置一个 Camera.PreviewCallback,在这个回调中实现一个方法onPreviewFrame(byte[] data, Camera camera),就可以去Camera预览图片时的数据。

    当然如果设置了camera.setPreviewCallback(callback),onPreviewFrame这个方法会被一直调用,可以在摄像头对焦成功后设置camera.setOneShotPreviewCallback(previewCallback),这样设置onPreviewFrame这个方法就会被调用一次,处理data数据,bitmap来做相应的处理就行了。这两个方法都是系统自动配置缓冲区。
    setPreviewFormat 函数可以设置预览是onPreviewFrame返回数据的格式。
    最常见的获取的数据格式为NV21,如果不设置默认返回数据也是NV21编码的数据。

    Camera.Parameters parameters = mCamera.getParameters();
    parameters.setRecordingHint(true);
    {
        //设置获取数据的格式
        parameters.setPreviewFormat(ImageFormat.NV21);
        //parameters.setPreviewFormat(ImageFormat.YV12);
    
        //通过setPreviewCallback方法监听预览的回调:
        byte[] imageByte;
        Bitmap bitmap;
        mCamera.setPreviewCallback(new Camera.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] bytes, Camera camera) {
                //这里面的Bytes的数据就是NV21格式的数据,或者YV12的数据
                Camera.Size previewSize = camera.getParameters().getPreviewSize();//获取尺寸,格式转换的时候要用到
            BitmapFactory.Options newOpts = new BitmapFactory.Options();
            newOpts.inJustDecodeBounds = true;
            YuvImage yuvimage = new YuvImage(
                    data,
                    ImageFormat.NV21,
                    previewSize.width,
                    previewSize.height,
                    null);
            baos = new ByteArrayOutputStream();
            yuvimage.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 100, baos);// 80--JPG图片的质量[0-100],100最高
            imageByte = baos.toByteArray();
            //将imageByte转换成bitmap
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            bitmap = BitmapFactory.decodeByteArray(imageByte, 0, imageByte.length, options);
            }
        });
    
    }
    mCamera.setParameters(parameters);
    

    注意,onPreviewFrame()方法跟Camera.open()是运行于同一个线程,所以为了防止onPreviewFrame()会阻塞UI线程,将Camera.open()放置在子线程中运行。

    为什么要用到这个函数,因为如果调用takePicture别管怎么设置界面都会卡顿,如果通过onPreviewFrame的回调处理函数,不会导致界面卡顿。

    setPreviewCallbackWithBuffer 类似setPreiewCallback,一般配合setPreviewCallback使用
    setPreviewCallbackWithBuffer (Camera.PreviewCallback cb) 要求指定一个字节数组作为缓冲区,用于预览帧数据,这样能够更好的管理预览帧数据时使用的内存。

    setPreviewCallbackWithBuffer需要在startPreview()之前调用,因为setPreviewCallbackWithBuffer使用时需要指定一个字节数组作为缓冲区,用于预览帧数据,所以我们需要在setPreviewCallbackWithBuffer之前调用addCallbackBuffer,这样onPreviewFrame的data才有值。然后需要在onPreviewFrame中调用,如果在onPreviewFrame中不调用,那么预览帧数据就不会回调给onPreviewFrame。

    代码示例:

    //通过setPreviewCallback方法监听预览的回调:
                    mCamera.setPreviewCallback(new Camera.PreviewCallback() {
                        @Override
                        public void onPreviewFrame(byte[] bytes, Camera camera) {
                            //这里面的Bytes的数据就是NV21格式的数据,或者YUV_420_888的数据
                        }
                    });
    
                    mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
                        @Override
                        public void onPreviewFrame(byte[] data, Camera camera) {
    
                        }
                    });
                }
    
                mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
                    @Override
                    public void onPreviewFrame(byte[] data, Camera camera) {
                        
                    }
                });
    

    8 其他

    camera的切换(前后摄像头)

    要先释放前一个Camera,然后打开新相机,打开预览。

    takePicture获取图片

    调用takePicture后预览会停止,需用重新调用startPreview才能再次开始预览。预览开始后,就可以通过Camera.takePicture()方法拍摄一张照片,返回的照片数据通过Callback接口获取。
    takePicture()接口可以获取三个类型的照片:
    第一个,ShutterCallback接口,在拍摄瞬间瞬间被回调,通常用于播放“咔嚓”这样的音效;
    第二个,PictureCallback接口,返回未经压缩的RAW类型照片;
    第三个,PictureCallback接口,返回经过压缩的JPEG类型照片;

    是否支持自动对焦

    List modes = Parameters.getSupportedFocusModes();
    modes.contains(Camera.Parameters.FOCUS_MODE_AUTO);
    getSupportedFocusModes函数获取所有的焦点模式,FOCUS_MODE_AUTO标识自动对焦,对焦方式还有FOCUS_MODE_CONTINUOUS_VIDEO使用视频录制,FOCUS_MODE_CONTINUOUS_PICTURE 用于拍照。

    9 简单实例:

    public class Main23Activity extends AppCompatActivity implements SurfaceHolder.Callback ,SensorEventListener{
        private static int mOrientation = 0;
        private static int mCameraID = Camera.CameraInfo.CAMERA_FACING_BACK;
        private CustomSurfaceView mSurfaceView;
        private SurfaceHolder mSurfaceHolder;
        private Camera mCamera;
        private boolean havePermission = false;
        private Button btnFocus;
        private Button btnTakePic;
        private Button btnRestar;
        private Button btnChange;
        private int useWidth;
        private int useHeight;
        private SensorManager mSensorManager;
        private Sensor mSensor;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main23);
    
            btnFocus = findViewById(R.id.focus);
            btnTakePic = findViewById(R.id.takepic);
            btnRestar = findViewById(R.id.restar);
            btnChange = findViewById(R.id.change);
    
            btnChange.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    switchCamera();
                }
            });
    
            btnRestar.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(mCamera != null){
                        mCamera.startPreview();
                    }
                }
            });
            btnFocus.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mCamera != null && mCameraID == Camera.CameraInfo.CAMERA_FACING_BACK){
                        mCamera.autoFocus(new Camera.AutoFocusCallback() {
                            @Override
                            public void onAutoFocus(boolean success, Camera camera) {
                                if(success){
                                    Toast.makeText(Main23Activity.this,"对焦成功",Toast.LENGTH_SHORT).show();
                                }else{
    
                                }
                            }
                        });
                    }
                }
            });
    
            btnTakePic.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(mCamera!= null){
                        mCamera.takePicture(null, null, new Camera.PictureCallback() {
                            @Override
                            public void onPictureTaken(byte[] data, Camera camera) {
                                // 获取Jpeg图片,并保存在sd卡上
                                String path = Environment.getExternalStorageDirectory()
                                        .getPath()  +"/focus/";
                                File pathDir = new File(path);
                                if (!pathDir.exists()){
                                    pathDir.mkdir();
                                }
                                File pictureFile = new File(path+ "focusdemo.jpg");
                                if (pictureFile.exists()){
                                    pictureFile.delete();
                                }
                                try {
                                        FileOutputStream fos = new FileOutputStream(pictureFile);
                                        fos.write(data);
                                        fos.close();
                                    } catch (Exception e) {
    
                                    }
                            }
                        });
                    }
                }
            });
    
            mSensorManager = (SensorManager) Main23Activity.this.getSystemService(Activity.SENSOR_SERVICE);
            mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);// 加速度
    
            // Android 6.0相机动态权限检查,省略了
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                    == PackageManager.PERMISSION_GRANTED &&
                    ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                            == PackageManager.PERMISSION_GRANTED) {
                havePermission = true;
                init();
            } else {
                havePermission = false;
                ActivityCompat.requestPermissions(this,
                        new String[]{
                                Manifest.permission.CAMERA,
                                Manifest.permission.WRITE_EXTERNAL_STORAGE
                        }, 100);
    
            }
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            mSensorManager.unregisterListener(this,mSensor);
        }
    
        public void releaseCamera(){
            if (mCamera != null) {
                mSurfaceHolder.removeCallback(this);
                mCamera.setPreviewCallback(null);
                mCamera.stopPreview();
                mCamera.lock();
                mCamera.release();
                mCamera = null;
    
            }
        }
    
        public void switchCamera(){
            if(mCameraID ==  Camera.CameraInfo.CAMERA_FACING_BACK){
                mCameraID =  Camera.CameraInfo.CAMERA_FACING_FRONT;
            }else{
    
              mCameraID =  Camera.CameraInfo.CAMERA_FACING_BACK;
    
            }
            try {
                initCamera();
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public void init(){
            if(mSurfaceView == null){
                mSurfaceView = findViewById(R.id.surfaceview);
                mSurfaceView.setCustomEvent(new CustomSurfaceView.ONTouchEvent() {
                    @Override
                    public void onTouchEvent(MotionEvent event) {
                        handleFocus(event, mCamera);
                    }
                });
                mSurfaceHolder = mSurfaceView.getHolder();
                mSurfaceHolder.addCallback(this);
                WindowManager wm = (WindowManager) Main23Activity.this.getSystemService(Context.WINDOW_SERVICE);
                int width = wm.getDefaultDisplay().getWidth();
                LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) mSurfaceView.getLayoutParams();
                layoutParams.width = width;
                layoutParams.height = width*4/3;
                useWidth = width;
                useHeight = width*4/3;
                mSurfaceView.setLayoutParams(layoutParams);
            }
    
        }
    
        private void initCamera() {
            if (mCamera != null){
                releaseCamera();
                System.out.println("===================releaseCamera=============");
            }
            mCamera = Camera.open(mCameraID);
            System.out.println("===================openCamera=============");
            if (mCamera != null){
                try {
                    mCamera.setPreviewDisplay(mSurfaceHolder);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                Camera.Parameters parameters = mCamera.getParameters();
                parameters.setRecordingHint(true);
                {
                    //设置获取数据
                    parameters.setPreviewFormat(ImageFormat.NV21);
                    //parameters.setPreviewFormat(ImageFormat.YUV_420_888);
    
                    //通过setPreviewCallback方法监听预览的回调:
                    mCamera.setPreviewCallback(new Camera.PreviewCallback() {
                        @Override
                        public void onPreviewFrame(byte[] bytes, Camera camera) {
                            //这里面的Bytes的数据就是NV21格式的数据,或者YUV_420_888的数据
    
    
                        }
                    });
                }
    
                if(mCameraID == Camera.CameraInfo.CAMERA_FACING_BACK){
                    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                }
    
                mCamera.setParameters(parameters);
    
                calculateCameraPreviewOrientation(this);
                Camera.Size tempSize = setPreviewSize(mCamera, useHeight,useWidth);
                {
                    //此处可以处理,获取到tempSize,如果tempSize和设置的SurfaceView的宽高冲突,重新设置SurfaceView的宽高
                }
    
                setPictureSize(mCamera,  useHeight,useWidth);
                mCamera.setDisplayOrientation(mOrientation);
                int degree = calculateCameraPreviewOrientation(Main23Activity.this);
                mCamera.setDisplayOrientation(degree);
                mCamera.startPreview();
            }
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
    
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            //当SurfaceView变化时也需要做相应操作,这里未做相应操作
            if (havePermission){
                initCamera();
            }
    
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            mCamera.stopPreview();
        }
    
        private void setPictureSize(Camera camera ,int expectWidth,int expectHeight){
            Camera.Parameters parameters = camera.getParameters();
            Point point = new Point(expectWidth, expectHeight);
            Camera.Size size = findProperSize(point,parameters.getSupportedPreviewSizes());
            parameters.setPictureSize(size.width, size.height);
            camera.setParameters(parameters);
        }
    
        private Camera.Size setPreviewSize(Camera camera, int expectWidth, int expectHeight) {
            Camera.Parameters parameters = camera.getParameters();
            Point point = new Point(expectWidth, expectHeight);
            Camera.Size size = findProperSize(point,parameters.getSupportedPictureSizes());
            parameters.setPictureSize(size.width, size.height);
            camera.setParameters(parameters);
            return size;
        }
    
        /**
         * 找出最合适的尺寸,规则如下:
         * 1.将尺寸按比例分组,找出比例最接近屏幕比例的尺寸组
         * 2.在比例最接近的尺寸组中找出最接近屏幕尺寸且大于屏幕尺寸的尺寸
         * 3.如果没有找到,则忽略2中第二个条件再找一遍,应该是最合适的尺寸了
         */
        private static Camera.Size findProperSize(Point surfaceSize, List<Camera.Size> sizeList) {
            if (surfaceSize.x <= 0 || surfaceSize.y <= 0 || sizeList == null) {
                return null;
            }
    
            int surfaceWidth = surfaceSize.x;
            int surfaceHeight = surfaceSize.y;
    
            List<List<Camera.Size>> ratioListList = new ArrayList<>();
            for (Camera.Size size : sizeList) {
                addRatioList(ratioListList, size);
            }
    
            final float surfaceRatio = (float) surfaceWidth / surfaceHeight;
            List<Camera.Size> bestRatioList = null;
            float ratioDiff = Float.MAX_VALUE;
            for (List<Camera.Size> ratioList : ratioListList) {
                float ratio = (float) ratioList.get(0).width / ratioList.get(0).height;
                float newRatioDiff = Math.abs(ratio - surfaceRatio);
                if (newRatioDiff < ratioDiff) {
                    bestRatioList = ratioList;
                    ratioDiff = newRatioDiff;
                }
            }
    
            Camera.Size bestSize = null;
            int diff = Integer.MAX_VALUE;
            assert bestRatioList != null;
            for (Camera.Size size : bestRatioList) {
                int newDiff = Math.abs(size.width - surfaceWidth) + Math.abs(size.height - surfaceHeight);
                if (size.height >= surfaceHeight && newDiff < diff) {
                    bestSize = size;
                    diff = newDiff;
                }
            }
    
            if (bestSize != null) {
                return bestSize;
            }
    
            diff = Integer.MAX_VALUE;
            for (Camera.Size size : bestRatioList) {
                int newDiff = Math.abs(size.width - surfaceWidth) + Math.abs(size.height - surfaceHeight);
                if (newDiff < diff) {
                    bestSize = size;
                    diff = newDiff;
                }
            }
    
            return bestSize;
        }
    
        private static void addRatioList(List<List<Camera.Size>> ratioListList, Camera.Size size) {
            float ratio = (float) size.width / size.height;
            for (List<Camera.Size> ratioList : ratioListList) {
                float mine = (float) ratioList.get(0).width / ratioList.get(0).height;
                if (ratio == mine) {
                    ratioList.add(size);
                    return;
                }
            }
    
            List<Camera.Size> ratioList = new ArrayList<>();
            ratioList.add(size);
            ratioListList.add(ratioList);
        }
        /**
         * 排序
         * @param list
         */
        private static void sortList(List<Camera.Size> list) {
            Collections.sort(list, new Comparator<Camera.Size>() {
                @Override
                public int compare(Camera.Size pre, Camera.Size after) {
                    if (pre.width > after.width) {
                        return 1;
                    } else if (pre.width < after.width) {
                        return -1;
                    }
                    return 0;
                }
            });
        }
    
        /**
         * 设置预览角度,setDisplayOrientation本身只能改变预览的角度
         * previewFrameCallback以及拍摄出来的照片是不会发生改变的,拍摄出来的照片角度依旧不正常的
         * 拍摄的照片需要自行处理
         * 这里Nexus5X的相机简直没法吐槽,后置摄像头倒置了,切换摄像头之后就出现问题了。
         * @param activity
         */
        public static int calculateCameraPreviewOrientation(Activity activity) {
            Camera.CameraInfo info = new Camera.CameraInfo();
            Camera.getCameraInfo(mCameraID, info);
            int rotation = activity.getWindowManager().getDefaultDisplay()
                    .getRotation();
            int degrees = 0;
            switch (rotation) {
                case Surface.ROTATION_0:
                    degrees = 0;
                    break;
                case Surface.ROTATION_90:
                    degrees = 90;
                    break;
                case Surface.ROTATION_180:
                    degrees = 180;
                    break;
                case Surface.ROTATION_270:
                    degrees = 270;
                    break;
            }
    
            int result;
            if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                result = (info.orientation + degrees) % 360;
                result = (360 - result) % 360;
            } else {
                result = (info.orientation - degrees + 360) % 360;
            }
            mOrientation = result;
            System.out.println("=========orienttaion============="+result);
            return result;
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            mSensorManager.registerListener(this, mSensor,
                    SensorManager.SENSOR_DELAY_NORMAL);
            if (havePermission && mCamera != null)
           mCamera.startPreview();
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            if (havePermission && mCamera != null)
          mCamera.stopPreview();
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            switch (requestCode) {
                // 相机权限
                case 100:
                    havePermission = true;
                    init();
                    break;
            }
        }
    
        /**
         * 转换对焦区域
         * 范围(-1000, -1000, 1000, 1000)
         */
        private  Rect calculateTapArea(float x, float y,  int width, int height, float coefficient) {
            float focusAreaSize = 200;
            int areaSize = (int) (focusAreaSize * coefficient);
            int surfaceWidth = width;
            int surfaceHeight = height;
            int centerX = (int) (x / surfaceHeight * 2000 - 1000);
            int centerY = (int) (y / surfaceWidth * 2000 - 1000);
            int left = clamp(centerX - (areaSize / 2), -1000, 1000);
            int top = clamp(centerY - (areaSize / 2), -1000, 1000);
            int right = clamp(left + areaSize, -1000, 1000);
            int bottom = clamp(top + areaSize, -1000, 1000);
            return new Rect(left, top, right, bottom);
        }
    
        //不大于最大值,不小于最小值
        private  int clamp(int x, int min, int max) {
            if (x > max) {
                return max;
            }
            if (x < min) {
                return min;
            }
            return x;
        }
    
        private  void handleFocus(MotionEvent event, Camera camera) {
            int viewWidth = useWidth;
            int viewHeight = useHeight;
            Rect focusRect = calculateTapArea(event.getX(), event.getY(),  viewWidth, viewHeight,1.0f);
    
            //一定要首先取消
            camera.cancelAutoFocus();
            Camera.Parameters params = camera.getParameters();
            if (params.getMaxNumFocusAreas() > 0) {
                List<Camera.Area> focusAreas = new ArrayList<>();
                focusAreas.add(new Camera.Area(focusRect, 800));
                params.setFocusAreas(focusAreas);
            } else {
                //focus areas not supported
            }
            //首先保存原来的对焦模式,然后设置为macro,对焦回调后设置为保存的对焦模式
            final String currentFocusMode = params.getFocusMode();
            params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
            camera.setParameters(params);
    
            camera.autoFocus(new Camera.AutoFocusCallback() {
                @Override
                public void onAutoFocus(boolean success, Camera camera) {
                    //回调后 还原模式
                    Camera.Parameters params = camera.getParameters();
                    params.setFocusMode(currentFocusMode);
                    camera.setParameters(params);
                    if(success){
                        Toast.makeText(Main23Activity.this,"对焦区域对焦成功",Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    
        @Override
        public void onSensorChanged(SensorEvent event) {
            //手机移动一段时间后静止,然后静止一段时间后进行对焦
            // 读取加速度传感器数值,values数组0,1,2分别对应x,y,z轴的加速度
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                int x = (int) event.values[0];
                int y = (int) event.values[1];
                int z = (int) event.values[2];
    
            }
        }
    
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
    
        }
    }
    

    在这里插入图片描述
    上面的实例代码支持,触摸对焦,自动对焦,拍照,摄像头切换,其他更多高级内容后续会接着讲。

    展开全文
  • camera基本原理

    2019-06-13 16:46:43
    http://blog.csdn.net/xubin341719/article/details/7723725 http://blog.csdn.net/pengwentao/article/details/7180115 http://blog.csdn.net/southcamel/article/details/8305873 ...
  • Camera2使用

    千次阅读 2019-03-31 21:43:29
    随着android9.0的发布,android系统相机换成了Camera2,所以我们也要适配的。 流程示意图 主要类 要枚举,查询和打开可用的摄像头设备,请获取CameraManager实例。 CameraManager manager = (CameraManager...
  • Camera1、Camera2 API的使用

    千次阅读 2019-09-05 15:28:22
    Camera1 使用流程: 检查相机权限(android.permission.CAMERACamera.getNumberOfCameras():获取相机硬件数量; Camera.getCameraInfo():获取指定相机信息; Camera.open():打开指定相机; camera.get...
  • camera2 开发demo记录

    千次阅读 2019-06-24 11:00:11
    camera2开发,谷歌提供了两个demo,android-Camera2Basic和android-Camera2Raw. android-Camera2Basic: 使用这个demo,出现了在光线暗的情况下拍照(不开闪光灯),不出图片(即onImageAvailable(ImageReader reader)...
  • camera录像过程一

    2019-01-25 13:54:25
    camera 的录像分为三个过程:  camera模块将从hal层的预览线程中,获取原始的未压缩的yvu视屏帧,通过回调函数传递到CameraSource模块  OMXCodec模块将从CameraSource模块的read接口获取yuv视频帧拷贝到编码模块...
  • Camera1 调用摄像机预览+获取每一帧

    千次阅读 2019-04-29 14:09:30
    使用camera1调试相机预览+获取每一帧数据, https://www.jianshu.com/p/3440d82545f6 https://www.jianshu.com/p/705d4792e836 主要学习代码,在这里 MainActivity public class MainActivity extends ...
  • 树莓派(Raspberry Pi)中PiCamera+OpenCV的使用

    万次阅读 多人点赞 2017-04-19 20:14:37
    树莓派(Raspberry Pi)中PiCamera+OpenCV的使用参考:Raspberry Pi:https://www.raspberrypi.org/ Index of Packages:https://pypi.python.org/pypi/picamera最新版本是 picamera 1.13:...
  • Python调用海康SDK实时显示网络摄像头一. 准备工作1.下载海康SDK2.安装配置OpenCV3.安装配置swig4.下载boost库5.下载OpenCV-swig接口文件二. 使用SWIG编译生成python和C++数据交换需要的.py和.cxx 文件三....
  • Camera Link相机接口

    万次阅读 2018-03-05 20:46:43
    关于FPGA采集卡实现的简要技术说明1介绍Camera Link是工业相机中使用的标准接口。它由多个使用差分信号的串行链路组成。根据要传输的数据量,每台摄像机可以使用一条或两条电缆。自动影像协会是Camera Link标准的...
  • Cameralink学习笔记

    千次阅读 2019-03-31 10:51:56
    首先对于Cameralink的相关介绍转自下面的文档: https://wenku.baidu.com/view/7470181779563c1ec5da71ec.html(Cameralink简介) https://wenku.baidu.com/view/ff8a623181c758f5f71f673f.html(cameralink_v2.0...
  • 基于现场可编程门阵列(FPGA) XC6LX100T 设计了两套 CameraLink 接口传输的硬 件平台 ,提出在实验中结合使用片上调试工具 Chipscope 和同步发生源模块用于精确测量 FPGA 中 的 传 输 误 码 的 方 法 ,详 细 ...
  • cameraLink

    2019-01-04 16:22:29
    cameraLink 编辑 2000年10月美国NI、摄像头供应商和其他图像采集公司联合推出了CameraLink协议,CameraLink协议是一个工业高速串口数据和连接标准,旨简化图像采集接口,方便高速数字相机和数据采集卡的连接。 ...
  • Cameralink资料整理

    2018-03-06 11:16:52
    Camera Link 技术标准是基于 National Semiconductor 公司的 Channel Link 标准发展而来的,而 Channel Link 标准是一种多路并行 LVDS 传输接口标准。本资源包几乎含所有cameralink的讲义资源
  • cameralink详细介绍

    2018-02-24 10:59:01
    cameralink 接口内容以及应用的详细介绍,能让从事图像识别,模式识别人工智能的硬件工程师和软件工程师了解cameralink底层接口的方法
  • cameralink 标准协议

    2019-01-31 09:48:39
    cameralink 标准协议,用于cameralink相机图像解析,半导体行业硬件设计。
  • 因此,本文进行了基于 FPGA 的 Camera Link 相机图像采集及处理技术研 究,主要工作内容如下: 1) 设计了基于 FPGA 的图像采集调试平台; 2) 对图像采集调试平台进行了相应的硬件逻辑设计,实现了相机图像的实 时...
  • The following specifications provide a framework for Camera Link communication. The specifications are deliberately defined to be open, allowing camera and frame grabber manufacturers to differentiate...
  • CameraLink传输协议

    千次阅读 2019-06-30 22:01:06
    一、CameraLink协议是一种专门针对机器视觉应用领域的串行通信协议,它使用低压差分信号(LVDS)进行数据的传输和通信。CameraLink标准是在ChannelLink标准的基础上多加了6对差分信号线,其中4对用于并行传输相机控制...
  • camera link 接口说明

    2013-04-04 22:20:59
    关于camera link接口的2份入门资料
  • CameraLink标准解读

    千次阅读 2019-04-17 11:59:16
    LVDS信号:Low Voltage Differential Signal低压差分信号。低功耗、低误码率、低串扰和低辐射等特点,可以在PCB上传输,也可以用平衡电缆传输。差分终端电阻是100欧姆,差模电压(摆幅)在247mV到454mV之间,共模...
  • FPGA实现cameralink高清相机解码

    千次阅读 2019-09-28 10:10:40
    关于cameralink协议基本原理,这里不再赘述,CSDN和百度文库有大量的关于cameralink协议解读的文章,不过需要注意的是网上大量文章都是讲述如何用解码芯片(多是DS90CR288A),这些文章都写得很好,讲清了cameralink...
  • Camera Link协议 V2.0

    2018-12-13 12:39:54
    Camera-Link-v2.0-Feb10-2012-final-cameralink标准协议
  • 根据附件的原英文版cameralink协议,总结学习。 目录: 1.第一章 简介 2.第二章 信号需求 3.第三章 端口分配 4.第四章 bit分配 5.第五章 连接器 附录A 芯片组标准 附录B API 功能 附录C 不同配置(base medium full...
  • Cameralink通信协议Verilog源代码

    热门讨论 2013-01-18 13:04:15
    Cameralink通信协议FPGA的Verilog源代码
  • 基于LVDS电平标准的Cameralink传输()

    千次阅读 热门讨论 2018-12-04 16:04:38
     在以往的Cameralink相机采集中,通常会有协议解码芯片,但如今,在不使用解码芯片的情况下,直接由相机直接用Cameralink标准协议过LVDS直接把数据传输至FPGA。 二.协议介绍  一根时钟线,其余四根为数据线。均...
  • CameraLink简介

    万次阅读 2017-02-12 20:55:55
    CameraLink是一种专门针对机器视觉领域的通信协议,使用低压差分信号LVDS进行传输。它是在ChannelLink标准的基础上多增加了6对差分信号线,其中4对用于并行传输相机控制信号,其它2对用于相机和采集卡(或其他图像...

空空如也

1 2 3 4 5 ... 20
收藏数 202,484
精华内容 80,993
关键字:

camera