精华内容
下载资源
问答
  • ISP基本框架及算法介绍

    万次阅读 多人点赞 2018-05-20 01:30:29
    ISP基本框架及算法介绍 ISP(Image Signal Processor),即图像处理,主要作用是对前端图像传感器输出的信号做后期处理,主要功能有线性纠正、噪声去除、坏点去除、内插、白平衡、自动曝光控制等,依赖于ISP才能在...

    ISP基本框架及算法介绍

          ISP(Image Signal Processor),即图像处理,主要作用是对前端图像传感器输出的信号做后期处理,主要功能有线性纠正、噪声去除、坏点去除、内插、白平衡、自动曝光控制等,依赖于ISP才能在不同的光学条件下都能较好的还原现场细节,ISP技术在很大程度上决定了摄像机的成像质量。它可以分为独立与集成两种形式。

      

    ISP 的Firmware 包含三部分,一部分是ISP 控制单元和基础算法库,一部分是AE/AWB/AF 算法库,一部分是sensor 库。Firmware 设计的基本思想是单独提供3A 算法库,由ISP 控制单元调度基础算法库和3A 算法库,同时sensor 库分别向ISP 基础算法库和3A 算法库注册函数回调,以实现差异化的sensor 适配。ISP firmware 架构如下图所示。

    不同的sensor 都以回调函数的形式,向ISP 算法库注册控制函数。ISP 控制单元调度基础算法库和3A 算法库时,将通过这些回调函数获取初始化参数,并控制sensor,如调节曝光时间、模拟增益、数字增益,控制lens 步进聚焦或旋转光圈等。

    1. TestPattern------测试图像

        Test Pattern主要用来做测试用。不需要先在片上ROM存储图片数据,直接使用生成的测试图像,用生成的测试图像进行后续模块的测试验证。以下是常用的两种测试图像。

    2. BLC(BlackLevel Correction)------黑电平校正

           Black Level 是用来定义图像数据为 0 时对应的信号电平。由于暗电流的影响, 传感器出来的实际原始数据并不是我们需要的黑平衡( 数据不为0) 。 所以,为减少暗电流对图像信号的影响,可以采用的有效的方法是从已获得的图像信号中减去参考暗电流信号,或者更确切是:模拟信号很微弱的时候,有可能不能被A/D转换出来,导致光线很暗的时候,图像暗区细节丢失。因此,sensor一般会在A/D转换之前,给模拟信号一个偏移量,以确保输出的图像保留足够多的细节。而黑电平校正主要是通过标定的方式确定这个偏移量。使得后续ISP模块的处理在保持线性一致性的基础上进行。

            一般情况下, 在传感器中,实际像素要比有效像素多, 像素区头几行作为不感光区( 实际上, 这部分区域也做了 RGB 的 color filter) , 用于自动黑电平校正, 其平均值作为校正值, 然后在下面区域的像素都减去此矫正值, 那么就可以将黑电平矫正过来了。如下图所示,左边是做黑电平校正之前的图像,右边是做了黑电平校正之后的图像。

            黑电平校正是在一倍系统增益的情况下标定计算而来,有些sensor在高倍增益和低倍增益时,OB相差会比较大。这个时候就需要获取不同增益环境下的遮黑RAW数据,分析R/Gr/Gb/B四个通道下的mean值。分析出来的均值即为各个通道的OB值。如果需要微调,即可在标定的OB上进行。例如:低照度下偏蓝,即可根据所在的ISO范围将B通道的幅度增加,减轻偏蓝现象。

         BLC原理及具体算法可以参考:ISP——BLC(Black Level Correction)

    3.LSC(Lens Shade Correction)------镜头阴影校正

         由于相机在成像距离较远时,随着视场角慢慢增大,能够通过照相机镜头的斜光束将慢慢减少,从而使得获得的图像中间比较亮,边缘比较暗,这个现象就是光学系统中的渐晕。由于渐晕现象带来的图像亮度不均会影响后续处理的准确性。因此从图像传感器输出的数字信号必须先经过镜头矫正功能块来消除渐晕给图像带来的影响。同时由于对于不同波长的光线透镜的折射率并不相同,因此在图像边缘的地方,其R、G、B的值也会出现偏差,导致CA(chroma aberration)的出现,因此在矫正渐晕的同时也要考虑各个颜色通道的差异性。

        常用的镜头矫正的具体实现方法是,首先确定图像中间亮度比较均匀的区域,该区域的像素不需要做矫正;以这个区域为中心,计算出各点由于衰减带来的图像变暗的速度,这样就可以计算出相应R、G、B通道的补偿因子(即增益)。下图左边图像是未做镜头阴影校正的,右边图像是做了镜头阴影校正的。

        出于节约成本的考虑以及尺寸方面的原因,手机相机镜头向小型化和低成本方向发展。由于摄像头尺寸小,制造材料品质低,拍摄的图像在靠近边缘处会出现亮度衰减的现象。因此要对 Bayer raw 图像进行镜头衰减校正,以降低计算负荷。使用 LUT 分段线性近似法代替模拟曲线和多项式运算。每种颜色都有自己的 LUT,因此亮度衰减和色偏问题可同时得到解决。

       针对不同增益下的LSC校正强度也会有所不一样。低照度下相对会比正常光照情况下校正强度要小一些。因此,ISP会预留接口以便对不同增益下的LSC强度进行调整。抑或者预留接口控制图像不同区域的LSC校正强度。例如:从中心区域开始往图像四周校正强度逐级减弱。

         具体算法原理可以参考:ISP之LSC

                                                        LSC校准原理

                                                  LSC校准前后结果对比

    4.DPC(Bad Point Correction)------坏点校正

         所谓坏点,是指像素阵列中与周围像素点的变化表现出明显不同的像素,因为图像传感器是成千上万的元件工作在一起,因此出现坏点的概率很大。一般来讲,坏点分为三类:第一类是死点,即一直表现为最暗值的点;第二类是亮点,即一直表现为最亮值的点:第三类是漂移点,就是变化规律与周围像素明显不同的像素点。由于图像传感器中CFA的应用,每个像素只能得到一种颜色信息,缺失的两种颜色信息需要从周围像素中得到。如果图像中存在坏点的话,那么坏点会随着颜色插补的过程往外扩散,直到影响整幅图像。因此必须在颜色插补之前进行坏点的消除。

        盐椒噪声是一种在图像中产生黑点或白点的脉冲噪声,这类噪声往往和图像信号内容不相关,与邻域周边像素灰度值差别明显。中值滤波能够较好的滤除盐椒噪声(冲激噪声)。对于Sensor坏点来说,在一定程度上也可以看做是盐椒噪声,因此,坏点校正也可以使用中值滤波进行滤除。

       算法基本原理:

          以图1.10中P4点为例,坏点消除基本过程为:首先计算该像素点与周围像素点像素值的差:

          设定一个阈值,作为判断的标准。判断各个方向上的差值跟阈值的关系,如果都大于阈值的话,就表明该点像素值与周围像素点的差别较大,就可以确定该像素点为坏点,否则该像素就为正常的像素点,可以进行下一个像素点的处理。

          若判断出某点为坏点,接下来进行对其的校正,过程如下:计算该点各个方向上的导数:

         确定出该值最小的方向,表明该像素点需要在该方向上进行补偿,则按照下面的公式对该像素进行补偿,即若假设有

    ((DV<=DH) && (DV<DDL)&&(DV<=DDR))

        则该像素点的值可以用下面的值来取代 

    Avg = (p1+2*p4+p4)/4

    其他DPC校正算法也可以参考脉冲噪声及其消除算法(DPC)以及适于硬件实现的中值滤波算法

    5.GB(Green Balance)------绿平衡

        由于感光器件制造工艺和电路问题,Gr,Gb数值存在差异,将出现格子迷宫现象可使用均值算法处理Gr,Gb通道存在的差异,同时保留高频信息。

       另外一个说法是:

        Sensor芯片的Gr,Gb通道获取的能量或者是输出的数据不一致,造成这种情况的原因之一是Gr,GB通道的半导体制造工艺方面存在差异,另一方面是Microlens的存在,特别是sensor边缘区域,GB,Gr因为有角度差异,导致接收到的光能不一致。如果两者差异比较大,就会出现类似迷宫格子情况。主要是考虑G周围的G的方法进行平均化

                                                            Optical cross-talk示意图

      算法基本原理:

    A 5x5 local window from Bayer GRBG pattern, (a) The central pixel G7 is Gr; (b) the central pixel G7 is Gb
    • 基于插值的方法

    该算法中,选取Gr或Gb为参考颜色通道,修改另一个G通道分量,使得Gr/Gb两通道的数值基本一致。

    假设Gb作为参考通道a图中的位于位置7的Gr像素值应该按照如下公式修改:

     如果选择Gr为参考通道,则只需要按照同样的方法修改Gb的像素值即可

    • 基于平均值的方法

    该算法中Gr,Gb两个通道中的像素值都需要修改。

    图a中,对于位于7位置的Gr,需要按照如下公式修:

     图b中,对于位于7位置的Gb,需要按照如下公式修改:

    6.Denoise-----去除噪声

        使用 cmos sensor 获取图像,光照程度和传感器问题是生成图像中大量噪声的主要因素。同时, 当信号经过 ADC 时, 又会引入其他一些噪声。 这些噪声会使图像整体变得模糊, 而且丢失很多细节, 所以需要对图像进行去噪处理空间去噪传统的方法有均值滤波、 高斯滤波等。

        但是, 一般的高斯滤波在进行采样时主要考虑了像素间的空间距离关系, 并没有考虑像素值之间的相似程度, 因此这样得到的模糊结果通常是整张图片一团模糊。 所以, 一般采用非线性去噪算法, 例如双边滤波器, 在采样时不仅考虑像素在空间距离上的关系, 同时加入了像素间的相似程度考虑, 因而可以保持原始图像的大体分块, 进而保持边缘。

       关于2D denoise可以参考:一种基于bayer型模式的双边自适应滤波器

    7.Demosaic------颜色插值

        光线中主要包含三种颜色信息,即R、G、B。但是由于像素只能感应光的亮度,不能感应光的颜色,同时为了减小硬件和资源的消耗,必须要使用一个滤光层,使得每个像素点只能感应到一种颜色的光。目前主要应用的滤光层是bayer GRBG格式。如下图所示:

        这样,经过滤色板的作用之后,每个像素点只能感应到一种颜色。必须要找到一种方法来复原该像素点其它两个通道的信息,寻找该点另外两个通道的值的过程就是颜色插补的过程。由于图像是连续变化的,因此一个像素点的R、G、B的值应该是与周围的像素点相联系的,因此可以利用其周围像素点的值来获得该点其它两个通道的值。目前最常用的插补算法是利用该像素点周围像素的平均值来计算该点的插补值。如下图所示,左侧是RAW域原始图像,右侧是经过插值之后的图像。

    8.AWB(Automatic White Balance)------自动白平衡

        人类视觉系统具有颜色恒常性的特点,因此人类对事物的观察可以不受到光源颜色的影响。但是图像传感器本身并不具有这种颜色恒常性的特点,因此,其在不同光线下拍摄到的图像,会受到光源颜色的影响而发生变化。例如在晴朗的天空下拍摄到的图像可能偏蓝,而在烛光下拍摄到的物体颜色会偏红。因此,为了消除光源颜色对于图像传感器成像的影响,自动白平衡功能就是模拟了人类视觉系统的颜色恒常性特点来消除光源颜色对图像的影响的。

    9.CCM(Color Correction Matrix)------颜色校正

        颜色校正主要为了校正在滤光板处各颜色块之间的颜色渗透带来的颜色误差。一般颜色校正的过程是首先利用该图像传感器拍摄到的图像与标准图像相比较,以此来计算得到一个校正矩阵。该矩阵就是该图像传感器的颜色校正矩阵。在该图像传感器应用的过程中,及可以利用该矩阵对该图像传感器所拍摄的所有图像来进行校正,以获得最接近于物体真实颜色的图像。

        一般情况下,对颜色进行校正的过程,都会伴随有对颜色饱和度的调整。颜色的饱和度是指色彩的纯度,某色彩的纯度越高,则其表现的就越鲜明;纯度越低,表现的则比较黯淡。RGB三原色的饱和度越高,则可显示的色彩范围就越广泛。 

       一般在不同增益环境下CCM的饱和度会有所不同。例如,低照度小我们可以适当调低CCM饱和度以减轻低照度下色噪。因此,一般ISP会留出接口以便对不同增益下CCM饱和度调整,对一倍增益校正出的CCM参数进行插值计算,计算得到不同增益下较为合适的CCM参数。

            手动调整CCM参数原理可以参考:Color correction matrix(色彩矩阵)的学习思考

    10.RGB Gamma------Gamma校正

        伽马校正的最初起源是CRT屏幕的非线性,研究CRT电子枪的物理表明,电子枪的输入电压和输出光之间满足5.2幂函数关系,即荧光屏上显示的亮度正比于输入电压的5/2次方,这个指数被称为伽马。这种关系源于阴极、光栅和电子束之间的静电相互作用。由于对于输入信号的发光灰度,不是线性函数,而是指数函数,因此必需校正。Gamma校正的硬件实现方式可以参考: 一种基于分段线性插值的Gamma校正硬件实现Adaptive piece-wise approximation method for gamma correction

        但是实际情况是,即便CRT显示是线性的,伽马校正依然是必须的,是因为人类视觉系统对于亮度的响应大致是成对数关系的,而不是线性的。人类视觉对低亮度变化的感觉比高亮度变化的感觉来的敏锐,当光强度小于1lux时,常人的视觉敏锐度会提高100倍t2118]。伽马校正就是为了校正这种亮度的非线性关系引入的一种传输函数。校正过程就是对图像的伽玛曲线进行编辑,检出图像信号中的深色部分和浅色部分,并使两者比例增大,从而提高图像对比度效果,以对图像进行非线性色调编辑。由于视觉环境和显示设备特性的差异,伽马一般取2.2~2.5之间的值。当用于校正的伽马值大于1时,图像较亮的部分被压缩,较暗的部分被扩展;而伽马值小于1时,情况则刚好相反。

        现在常用的伽马校正是利用查表法来实现的,即首先根据一个伽马值,将不同亮度范围的理想输出值在查找表中设定好,在处理图像的时候,只需要根据输入的亮度,既可以得到其理想的输出值。在进行伽马校正的同时,可以一定范围的抑制图像较暗部分的噪声值,并提高图像的对比度。还可以实现图像现显示精度的调整,比如从l0bit精度至8bit精度的调整。上图分别是未做Gamma校正的,下图是做了Gamma校正的。

    11.RGBToYUV

        YUV 是一种基本色彩空间, 人眼对亮度改变的敏感性远比对色彩变化大很多, 因此, 对于人眼而言, 亮度分量 Y 要比色度分量 U、 V 重要得多。 另外,YUV色彩空间分为YUV444,YUV422,YUV420等格式,这些格式有些比原始RGB图像格式所需内存要小很多,这样亮度分量和色度分量分别存储之后,给视频编码压缩图像带来一定好处。

          RGB转YUV可以参考:色彩转换系列之RGB格式与YUV格式互转原理及实现

    12.WDR(Wide Dynamic Range)------宽动态

        动态范围(Dynamic Range)是指摄像机支持的最大输出信号和最小输出信号的比值,或者说图像最亮部分与最暗部分的灰度比值。普通摄像机的动态范围一般在1:1000(60db)左右,而宽动态(Wide Dynamic Range,WDR)摄像机的动态范围能达到1:1800-1:5600(65-75db)。

      宽动态技术主要用来解决摄像机在宽动态场景中采集的图像出现亮区域过曝而暗区域曝光不够的现象。简而言之,宽动态技术可以使场景中特别亮的区域和特别暗的区域在最终成像中同时看清楚。

    13.3DNR

             3dnr 是结合空域滤波和时域滤波的一种降噪算法。大概思路是检测视频的运动水平,更具运动水平的大小对图像像素进行空域滤波和时域滤波的加权,之后输出滤波之后的图像。

            基本原理可以参考:运动自适应降噪_Motion Adaptive Noise Reduction

    14.Sharp------锐化

        CMOS输入的图像将引入各种噪声,有随机噪声、量化噪声、固定模式噪声等。ISP降噪处理过程中,势必将在降噪的同时,把一些图像细节给消除了,导致图像不够清晰。为了消除降噪过程中对图像细节的损失,需要对图像进行锐化处理,还原图像的相关细节。如下图所示,左图是未锐化的原始图像,右图是经过锐化之后的图像。

        为了避免把Noise enhance出来,sharp在实现中还需要判断当前像素处于光滑区域还是物体边缘。当处于光滑区域的时候,则不要做sharp运算,或者做的幅度很小;只有在较明显的边缘上才做处理,这样避免不了边缘上的noise的影响,所以在锐利度s设定较大的时候,可以发现边缘上会有Noise闪动跳跃的情况。为了缓解这种Noise的跳跃,通常会对f(d, g, s)做最大值和最小值限制保护,并且沿着edge 方向做低通滤波来缓解Noise。

       sharp大致流程为先判断平坦区域还是边缘,对平坦区域可以不做或者少做sharp(甚至做smooth处理),对边缘要判断幅度大小,边缘方向,选则相对应的高通滤波器处理,最后对enhance的幅度做一定程度的保护处理。

    sharp算法基本原理(节选于《基于DSP的网络摄像机图像预处理技术》原文表述有些问题,已经按照作者想表达的意思进行的修改):

    边缘增强模块对图像的亮度分量(Y数据)进行操作来增强图像质量。首先按固定系数2D线性滤波器滤波计算边缘锐度sharpness(h,v)。sharp_shrink之后还可以结合查找表改变其锐化强度,然后再进行shoot的限制操作。

    clip与shrink函数表达式如下:

     两者函数图像如下图所示:

          shrink函数把高频锐化结果靠近0的部分都强制设为0,即比较平滑的部分不做锐化处理;远离0的部分适当减小其锐化强度。当高频锐化结果x比th比较大或比较小,如果x比th较大,那么适当在x的基础上减小一点,减低白边的锐化强度;如果x比-th较小,那么在x的基础上适当增加一点,降低黑边的锐化强度 。

    锐化前表现
    锐化后表现

    15.AF(Automatic Focus)----自动对焦

        自动对焦方面知识,可参考:

    1. 自动对焦模块理论基础及其硬件实现浅析(一)
    2. 自动对焦模块理论基础及其硬件实现浅析(二)
    3. 自动对焦模块理论基础及其硬件实现浅析(三)
    4. 自动对焦模块理论基础及其硬件实现浅析(四)

    16.AE(Automatic Exposure)----自动曝光

        不同场景下,光照的强度有着很大的差别。人眼有着自适应的能力因此可以很快的调整,使自己可以感应到合适的亮度。而图像传感器却不具有这种自适应能力,因此必须使用自动曝光功能来确保拍摄的照片获得准确的曝光从而具有合适的亮度。

        AE 模块实现的功能是:根据自动测光系统获得当前图像的曝光量,再自动配置镜头光圈、sensor快门及增益来获得最佳的图像质量。自动曝光的算法主要分光圈优先、快门优先、增益优先。光圈优先时算法会优先调整光圈到合适的位置,再分配曝光时间和增益,只适合p-iris 镜头,这样能均衡噪声和景深。快门优先时算法会优先分配曝光时间,再分配sensor增益和ISP 增益,这样拍摄的图像噪声会比较小。增益优先则是优先分配sensor增益和ISP 增益,再分配曝光时间,适合拍摄运动物体的场景。基本算法原理可以参考:3A+ISP之AE篇

        自动曝光的实现一般包括三个步骤:光强测量、场景分析和曝光补偿。光强测量的过程是利用图像的曝光信息来获得当前光照信息的过程。按照统计方式的不同,分为全局统计,中央权重统计或者加权平均统计方式等。全局统计方式是指将图像全部像素都统计进来,中央权重统计是指只统计图像中间部分,这主要是因为通常情况下图像的主体部分都位于图像的中间部分;加权平均的统计方式是指将图像分为不同的部分,每一部分赋予不同的权重,比如中间部分赋予最大权重,相应的边缘部分则赋予较小的权重,这样统计得到的结果会更加准确。场景分析是指为了获得当前光照的特殊情况而进行的处理,比如有没有背光照射或者正面强光等场景下。对这些信息的分析,可以提升图像传感器的易用性,并且能大幅度提高图像的质量,这是自动曝光中最为关键的技术。目前常用的场景分析的技术主要有模糊逻辑和人工神经网络算法。这些算法比起固定分区测光算法具有更高的可靠性,主要是因为在模糊规则制定或者神经网络的训练过程中已经考虑了各种不同光照条件。在完成了光强测量和场景分析之后,就要控制相应的参数使得曝光调节生效。主要是通过设定曝光时间和曝光增益来实现的。通过光强测量时得到的当前图像的照度和增益值与目标亮度值的比较来获得应该设置的曝光时间和增益调整量。在实际情况下,相机通常还会采用镜头的光圈/快门系统来增加感光的范围。

        在进行曝光和增益调整的过程中,一般都是变步长来调整的,这样可以提高调整的速度和精度。一般来讲,增益和曝光的步长设定如下图所示:

        从上图中可以看出,在当前曝光量与目标量差别在range0以内的时候,说明当前曝光已经满足要求,不需要进行调整;差别在rangel的范围内时,则说明当前曝光与要求的光照有差别,但差别不大,只需要用较小的步长来进行调节即可;当差别在range2的时候,则表明差别较大,需要用较大步长来进行调节。在实现过程中还需要注意算法的收敛性。

       实际应用中,AE曝光时间和增益的调整大致如下图所示:

     弱曝、过曝、曝光合适实际效果图:

          由于在对视频流做处理时,有些操作往往不是立即生效的。例如在自动曝光的处中,需要计算全局的亮度平均值。由于这个过程涉及到一帧中的所有像素点,所以在一帧图像输出完成之后才能得到亮度平均值。那么自动曝光所得到当前帧的计算结果,只能去调节下一帧的亮度,而无法影响当前帧。这个现象很普遍,只要程序存在全局的参数,就不可能在当前帧中得到计算结果。所以需要将第N帧数据计算出的参数或是结果,传递给第N+1帧,在第N+1帧中直接使用这个参数进行其他的计算,或者直接输出调整后的结果,我们将这种方法叫做帧迭代方法。虽然这个参数并不是根据地N+I帧数据计算出来的,但是由于相邻帧之间有很大的连续性,所以可以认为它们计算出来的全局变量是相同的,这样就可以实现正确并且实时的处理了。这种方法同样适用于AWB、3DNR、HDR模块。

          因此,当前帧显示的直方图以及亮度信息均是统计于前一帧的直方图和亮度信息,当前帧根据这些统计信息再进行AE策略的调整。

    以下部分转载自刘斯宁知乎专栏:Understanding Auto Exposure Control

    当曝光误差超过容许值需要调整时,算法需要计算两个值,即

    • 当前帧的曝光量,由sensor 曝光时间、sensor 增益、ISP 增益组成。需要注意的是,sensor 的曝光时间和增益通常是非连续的,很可能与AE算法输出的目标参数并不相同,所以当前曝光参数的准确值需要通过sensor 驱动从sensor 寄存器中直接读取,而不能使用AE算法缓存的目标值。
    • 增益系数,g=target/measured, 其中target 为理想画面亮度, measured 为当前画面亮度的实测值。 由于sensor 的本质是一个线性元件,若暂不考虑像素饱和等非线性因素,只要在当前曝光总量的基础上乘以系数g,就可以使画面目标亮度达到理想值。

    因此AE 算法的核心任务就是计算正确的g参数,这个参数能够使画面得到正确的曝光。

    当计算出正确的亮度参数后,一般并不会让其立刻在下一帧图像就生效。这是因为如果增益变化较大,图像就会产生闪烁,主观感受不好。通常人们更喜欢画面平滑过渡,因此每帧图像的增益变化不宜过大。实现平滑的方法就是给新的参数人为施加一个阻尼,使其缓慢地向新参数过渡。用数学公式描述就是

    g(n)= (1-s) * g(n-1) +s * g_target

    不妨取 s=0.2,此时每个g参数包含80%的旧参数和20%的目标参数,经过若干帧后旧参数自然衰减,新参数收敛到目标参数,即 g(n)=g_target

    从数学上看 (1-0.2)^10=0.1, (1-0.2)^30=0.001, 说明10帧之后(约0.3秒)旧参数的比重下降到10%,30帧之后(约1秒)旧参数的比重可忽略。对于典型的安防应用场景,一般建议经过8~16帧图像过渡到理想亮度。而对于运动和车载型应用,由于场景动态变化大且快,一般建议经过3~4帧图像过渡到理想亮度。

    具体计算:

    假设g(0) = 20; g_garget=45,则由阻尼公式可知:

    n=1时,g(1) = 0.8*20+0.2*45;

    n = 2时,g(2)=0.8*g(1)+0.2*45=0.8^{2}\star 20+0.2\star 0.8\star 45+0.2\star 45

    n=3时,g(3)=0.8*g(2)+0.2*45 = 0.8^{3}\star 20+0.2\star 0.8^{2}\star 45+0.2\star0.8\star 45+0.2\star 45

    n = 4时,g(4) = 0.8*g(3)+0.2*45 = 0.8^{4}\star 20+0.2\star 0.8^{3}\star 45+0.2\star0.8^{2}\star 45+0.2\star0.8\star 45+0.2\star 45

    \vdots \vdots

    当n=10时,g(10) = 0.8^{10}\star 20+\frac{1-0.8^{10}}{1-0.8}*0.2*45\approx =2+40.5=42.5

    参数分解

    当根据路径规划策略计算出下一帧的g参数后,需要遵循一定的策略和约束把g参数进一步映射为sensor 曝光时间、sensor 增益、ISP 增益等设备控制参数。如前所述,曝光时间可以提高图像信噪比,所以在约束边界内应尽可能先将曝光时间用满,然后依照sensor 的硬件约束分配sensor 增益,最后将剩余的增益全部分配给ISP 数字增益。

    5. 参数同步

    前面分解出来的控制参数必须同步生效才能使画面获得预期的曝光。如果某一项参数未能与其他几项同步生效,则画面会因为短暂过亮、过暗等原因出现闪烁,这是需要避免的。

    另一方面,所有参数都需要在一个特定的时间窗口内生效,即前一帧图像已经结束,新一帧图像尚未开始的这段时间,也就是sensor的垂直消隐(vertical blanking)窗口,这个窗口时间很短,典型值在3~5毫秒左右,更短的可以到1ms,如下图所示。

    目前主流的sensor都是使用I2C总线进行寄存器读写,而I2C总线的最大时钟频率是400kHz,读写一个16bit寄存器差不多每次需要0.1ms,而完成一帧图像的相关配置常常需要10~20次以上读写,所以在垂直消隐区完成sensor 寄存器配置时间压力是很大的。而且这还是单纯的配置参数,并不考虑3A算法本身所需的计算时间。实际上,在常见的软件硬件架构中,就是把全部消隐时间都分配给3A算法往往都是不够用的。

    如果配置sensor 增益时错过了这个窗口,新一帧图像已经开始,则画面的亮度就会在一帧中间发生变化,上半部分使用旧的参数,下半部分使用新的参数,这种情况也是闪烁的一种,是需要避免的。

    现在的sensor 为了方便使用,缓解配置参数时间窗口过短的压力,往往都支持一组影子(shadow)寄存器,需要同步生效的参数(曝光时间和增益)可以在任何时间点写入shadow寄存器,当sensor开始捕捉新的一帧图像之前,会自动把shadow 寄存器的内容同步到实际生效的寄存器,这样就把几个毫秒的时间窗口扩展成一帧时间,极大地缓解了用户压力。

    需要注意的是,虽然这个方案为软件争取到了一帧的缓冲时间,但同时也意味着系统的响应延迟(latency)增加了一帧,即根据第N帧统计数据生成的新控制参数只能在第N+2帧才开始生效,因为软件需要第在N+1帧时间内完成算法的计算工作。同理,根据第N+2帧统计生成的新控制参数需要在第N+4帧才开始生效,以此类推。因此,如果环境光照条件在第N+1帧发生剧变,算法会在第N+2帧结束时检测到画面异常,在第N+3帧中计算出新的参数,在第N+4帧中实际进行补偿。

    事实上,如果CPU的任务比较繁忙,或者每帧的时间很短,则一帧的时间可能还不一定够3A算法完成所有计算,此时则需要考虑继续增加一帧的缓冲时间。

    以下转载至camera杂项-曝光

    • 在跑3a算法时,曝光的改变策略
      1. 调试摄像头曝光很多时候都是以行算的,也就是常说的曝光行。当然算曝光时间是曝光行*每行的时间
      2. 一般曝光时间不超过vts,vts就是一帧花的总时间(包含每帧的无效信号)。因此,我们在计算当前帧最大曝光时间的时候,一般会根据VTS计算得出
      3. 除了曝光能增加亮度之外,gain也能增加亮度,gian也分为模拟gain和数字gain以及ISPgain
      4. 曝光时间引入的噪声最小,数字增益引入的噪声最大
      根据上面所说,假如在比较暗的情况下,为了减少噪声,势必先增加曝光时间。因为增加曝光时间引入的噪声最小,可以会略不计。但是当曝光时间超过当前vts时候,曝光时间超过一帧的时间,这样会引起帧率降低,那么这个时候可以增加gain值,模拟gain和数字gain都是有最大限制的,所有的增加gain值都是优先使用模拟gain,当模拟gain增加到最大之后,才考虑使用数字gain。

    • 关于3a中的ae,实际都有策略做曝光分解,在帧率与噪声中调和,在实际应用中,如果策略分解到曝光时间大于当前vts,那么正常需要先增加当前vts(每帧时间增加,也意味着帧率减小),然后加大曝光时间。

    • 写这些就能回答为什么亮的地方帧率会比暗的帧率高。

    参考资料:

    ISP概述、工作原理及架构

    相机系统综述 —— ISP

    Understanding Auto Exposure Control

    3A+ISP之ISP篇

    《CMOS sensor cross-talk compensation for digital cameras》

    《基于DSP的网络摄像机图像预处理技术》





     


     









     

    展开全文
  • [size=large][b]SSH框架简介[/b][/size]: SSH为struts+spring+hibernate的一个集成框架,是目前较流行的一种Web应用程序开源框架。〖建议对照图片阅读〗 1.集成SSH框架的系统从职责上分为四层:表示层、业务逻辑...
    [size=large][b]SSH框架简介[/b][/size]:
    
    SSH为struts+spring+hibernate的一个集成框架,是目前较流行的一种Web应用程序开源框架。〖建议对照图片阅读〗
    1.集成SSH框架的系统从职责上分为四层:表示层、业务逻辑层、数据持久层和域模块层,以帮助开发人员在短期内搭建结构清晰、可复用性好、维护方便的Web应用程序。其中使用Struts作为系统的整体基础架构,负责MVC的分离,在Struts框架的模型部分,控制业务跳转,利用Hibernate框架对持久层提供支持,Spring做管理,管理struts和hibernate。具体做法是:用面向对象的分析方法根据需求提出一些模型,将这些模型实现为基本的Java对象,然后编写基本的DAO(Data Access Objects)接口,并给出Hibernate的DAO实现,采用Hibernate架构实现的DAO类来实现Java类与数据库之间的转换和访问,最后由Spring做管理,管理struts和hibernate。
    2.系统的基本业务流程是: 在表示层中,首先通过JSP页面实现交互界面,负责接收请求(Request)和传送响应(Response),然后Struts根据配置文件(struts-config.xml)将ActionServlet接收到的Request委派给相应的Action处理。在业务层中,管理服务组件的Spring IoC容器负责向Action提供业务模型(Model)组件和该组件的协作对象数据处理(DAO)组件完成业务逻辑,并提供事务处理、缓冲池等容器组件以提升系统性能和保证数据的完整性。而在持久层中,则依赖于Hibernate的对象化映射和数据库交互,处理DAO组件请求的数据,并返回处理结果。
    采用上述开发模型,不仅实现了视图、控制器与模型的彻底分离,而且还实现了业务逻辑层与持久层的分离。这样无论前端如何变化,模型层只需很少的改动,并且数据库的变化也不会对前端有所影响,大大提高了系统的可复用性。而且由于不同层之间耦合度小,有利于团队成员并行工作,大大提高了开发效率。
    展开全文
  • APP 基本框架设计

    万次阅读 2016-12-14 13:52:17
    APP 基本框架设计 前言  一个良好的APP 基本遵循“简单”,“易用”,“高效”,“便维护”,“可扩展”基本也是从这几个原则出发,比较符合用户体验;同时也是比较符合我们开发人员设计程序的初衷,尽量低的耦合性...

    APP 基本框架设计

    前言

            一个良好的APP 基本遵循“简单”,“易用”,“高效”,“便维护”,“可扩展”基本也是从这几个原则出发,比较符合用户体验;同时也是比较符合我们开发人员设计程序的初衷,尽量低的耦合性和尽量高的可复用性,而一个设计良好的应用程序;必然需要有个比较规范和通用的设计框架,因此APP框架设计就变得尤为重要了.

    APP框架设计包括哪些内容

    APP框架搭建的设计;主要的核心思想还是分层思想,通常设计下,会包括以下内容:(如下图)


    APP框架搭建需要考虑的因数

    目前现在比较流行混合开发模式,而上图框架的设计内容是基于原生基础上设计,原生开发固然体验比较好,但是开发周期相对于网页通常比较长,对于混合开发模式;我们要考虑以下几个方面:

    1一般情况下;从用户体验的角度出发;为了提高用户体验;一般本地的一级页面,以及改动量比较小的页面,需要做成原生的。

    2 基于公司实际情况出发,经常变动版本;改动比较大的或者详情页面我们可以做成网页形式,便于我们版本迭代更新

    3复杂的软件必须有清晰合理的架构,否则无法后期扩展和维护;通常情况下;我们会结合业界比较成熟的一些设计模式;

    1 MVC 是最常见的软件架构之一,业界有着广泛应用,也是早期我们APP 设计时最常见的一种架构模式.


    § 视图(View):用户界面。

    § 控制器(Controller):业务逻辑

    § 模型(Model):数据保存

     

    MVC模式的意思是,软件可以分成三个部分。它们的通信方式

    1.View传送指令到 Controller

    2.Controller完成业务逻辑后,要求 Model改变状态

    3.Model将新的数据发送到 View,用户得到反馈.

    所有的通信都是单向的。

    2 MVP 模式作为一种新型模式,是从经典的模式MVC演变而来,它们的基本思想有相通的地方,将 Controller 改名为Presenter,同时改变了通信方向。


    1. 各个部分之间的通信,都是双向的。

    2. View 与 Model 不发生联系,都通过 Presenter传递

    3. View 非常薄,不部署任何业务逻辑,称为"被动视图",即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。

    4模型与视图完全分离,我们可以修改视图而不影响模型;

    5可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部;

    6我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁;

    7如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)

    3 MVVM (数据绑定) 最早是微软提出的;模式将 Presenter 改名为ViewModel,基本上与 MVP 模式完全一致。


    简单的说,ViewModel就是View与Model的连接器,View与Model通过ViewModel实现双向绑定。

    唯一的区别是,它采用双向绑定:View的变动,自动反映在 ViewModel,反之亦然.

    谷歌推出了Data binding这个框架,Data Binding是一个 support包,因此与 Android M没什么关系可以轻松的实现MVVMData binding解决了 Android UI 编程中的一个痛点,

    官方原生支持 MVVM 模型可以让我们在不改变既有代码框架的前提下,非常容易地使用这些新特性。

    其实在此之前,已经有些第三方的框架(RoboAndroid)

    可以支持 MVVM 模型,无耐由于框架的侵入性太强,导致一直没有流行起来。

     

    Data Binding 的基本用法

    一 环境  

    要求你的Android Studio版本是1.3+ 

    在开始之前,请更新你的Support repository到最新的版本

    要使用DataBinding,android的构建插件gradle要求1.5.0-alpha1或者更高的版本。

    二 添加依赖


    三Data Binding 入门级Demo 例子

    1 我们首先定义一个java bean  user

    2 我们再来写一个布局文件;如下图

    3最后来看看Activity怎么写。


    没有了之前的find控件,没有了setTextActivity代码更加简洁明了

    运行结果


    结合项目用的比较多的设计架构一般分为2种:

    A 单Activity+多Fragment的架构.

    B 多模块Activity+多Fragment的架构.

    是使用单Activity+多Fragment的架构,还是多模块Activity+多Fragment的架构?

    单Activity+多Fragment:
    一个app仅有一个Activity,界面皆是Frament,Activity作为app容器使用。

    优点:性能高,速度最快。参考:新版知乎 、google系app

    缺点:逻辑比较复杂,尤其当Fragment之间联动较多或者嵌套较深时,比较复杂。

    多模块Activity+多Fragment:
    一个模块用一个Activity,比如
    1、登录注册流程:
    LoginActivity + 登录Fragment+ 注册Fragment + 填写信息Fragment + 忘记密码Fragment
    2、或者常见的数据展示流程:
    DataActivity + 数据列表Fragment+ 数据详情Fragment + ...

    优点:速度快,相比较单Activity+多Fragment,更易维护。

    总结

    权衡利弊,我认为多模块Activity+多Fragment是最合适的架构,开发起来不是很复杂,app的性能又很高效。

    当然。Fragment只是官方提供的灵活组件,请优先遵从你的项目设计!真的特别复杂的界面,或者单个Activity就可以完成一个流程的界面,使用Activity可能是更好的方案。


    Android 的 Data Binding 框架还在 beta 阶段,Android Studio 对其内部支持也不是很完整,

    进步的空间还很大。不过它被设计和开发的很好,将会改变 Android 应用开发方式(如果顺利的话)。

    1 我个人比较倾向于采用了MVP+ Data Binding的混合模式.也就是比较流行热火的MVPVM模式。

    2如果有程序框架,因为项目的几乎是一致的,所以上一个项目的项目计划可以直接拿过来使用,而且经过几个项目之后,这个项目计划的模板会越来越细,越来越实用。

    因为结构一致,代码混乱性会降低到可以接受的程度,而且可以重用上一个项目的大部分代码。而且逻辑清晰,使得代码相对较小,不容易在代码中迷失。因为代码逻辑简单有序,所以测试起来会很容易。

    3 最后我们不能永远理想化地去选择所谓最好的设计,具体问题还得具体分析;在现实的必要情况下,我们要敢于舍弃,最合适的设计才是最好的设计.

    展开全文
  • ORM框架什么

    千次阅读 2017-01-11 23:12:55
    ORM框架什么  对象关系映射,目前数据库是关系型数据库  ORM 主要是把数据库中的关系数据映射称为程序中的对象 目前集中常见的ORM框架 1 Nhibernate 原因:用的比较多,资料也比较好找。 2 Castle...

    ORM框架是什么

     对象关系映射,目前数据库是关系型数据库  ORM 主要是把数据库中的关系数据映射称为程序中的对象

    目前集中常见的ORM框架
    1  Nhibernate
    原因:用的比较多,资料也比较好找。
    2  Castle ActiveRecord
    原因: 不用配置对象的XML文件,这点比Nhibernate爽
    3  EntityFramework
    原因:微软的东西(说真的,有点不想用)
    4  mybaits.net
    原因:我几个搞java的朋友都说他们现在不用hibernate了都在用mybaits。

    5 Dapper ORM

    假如你喜欢原生的Sql语句,又喜欢ORM的简单,那你一定会喜欢上Dapper这款ROM.点击下载
    Dapper的优势:
    1,Dapper是一个轻型的ORM类。代码就一个SqlMapper.cs文件,编译后就40K的一个很小的Dll.
    2,Dapper很快。Dapper的速度接近与IDataReader,取列表的数据超过了DataTable。
    3,Dapper支持什么数据库。Dapper支持Mysql,SqlLite,Mssql2000,Mssql2005,Oracle等一系列的数据库,当然如果你知道原理也可以让它支持Mongo db
    4,Dapper的r支持多表并联的对象。支持一对多 多对多的关系。并且没侵入性,想用就用,不想用就不用。无XML无属性。代码以前怎么写现在还怎么写。
    5,Dapper原理通过Emit反射IDataReader的序列队列,来快速的得到和产生对象。性能实在高高高。
    6,Dapper支持net2.0,3.0,3.5,4.0。【如果想在Net2.0下使用,可以去网上找一下Net2.0下如何配置运行Net3.5即可。】
    7,Dapper语法十分简单。并且无须迁就数据库的设计。

     

    下面介绍Dapper如何使用,来进行高效开发,以下操作是编译后在Net3.5下操作的例子,Net4.0下大部分函数有默认值,参数很简单。

     

    //数据库里的表:
    CREATE TABLE ColumnCat
    (
    Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    NAME NVARCHAR(150) NULL,
    ModifiedOn SMALLDATETIME NULL DEFAULT(GETDATE()),
    Parentid INT
    )
    
    CREATE TABLE Column
    (
    Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    NAME NVARCHAR(150) NULL,
    ModifiedDate SMALLDATETIME NULL DEFAULT(GETDATE()),
    ColumnCatid INT null
    )
    

     

    常用的表,分类和内容表,分类可以有下级类别。以下操作基本上都是对这两个表的操作。

     

    //连接数据库字符串。
    private readonly string sqlconnection =
                     "Data Source=RENFB;Initial Catalog=test;User Id=sa;Password=sa;";
    //public readonly string mysqlconnectionString =
                     @"server=127.0.0.1;database=test;uid=renfb;pwd=123456;charset='gbk'";
    

     

     

     

    //获取Sql Server的连接数据库对象。SqlConnection
    public SqlConnection OpenConnection()
    {
        SqlConnection connection = new SqlConnection(sqlconnection);
        connection.Open();
        return connection;
    }
    //获取MySql的连接数据库对象。MySqlConnection
    //public MySqlConnection OpenConnection()
    //{
    //     MySqlConnection connection = new MySqlConnection(mysqlconnectionString);
    //     connection.Open();
    //     return connection;
    //}
    

     

    注:如果需要换成Mysql数据库,只用将获得sql Server的连接数据库对象的函数注释掉,取消MySql的连接数据库对象的函数的注释,一并取消Mysql连接字符串的注释,并修改为自己的连接信息。

     

    Query()方法:
    Query()是IDbConnection扩展方法并且重载了,从数据库里提取信息,并用来填充我们的业务对象模型。

     

    //先创建一个类,是数据库的ColumnCat表的模型。
    public class ColumnCat
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime ModifiedOn { get; set; }
        public int Parentid { get; set; }
    }
    

     

     

     

    //获取ColumnCat对象的集合。
    public IEnumerable<ColumnCat> SelectColumnCats()
    {
        using (IDbConnection conn = OpenConnection())
        {
            const string query = "select * from ColumnCat order by id desc";
            return conn.Query<ColumnCat>(query,null);
        }
    }
    

     

    就是这么简单,直接在例子中嵌入Sql,很容易扩展为存储过程,可以使用别名使结果集中的列与业务对象模型(ColumnCat)的属性对应。

     

    //下面使用上面的集合显示出分类。
    List<ColumnCat> AllColumnCat =SelectColumnCats().ToList<ColumnCat>();
    foreach (ColumnCat cat in AllColumnCat.Where(c => c.Parentid == 0))
    {
        Response.Write("Name==>" + cat.Name + "\t");
        Response.Write("时间==>" + cat.ModifiedOn + "\t");
        Response.Write("<br/>");
    
        foreach (ColumnCat c in AllColumnCat
                    .Where<ColumnCat>(subColumnCat => subColumnCat.Parentid == cat.Id))
        {
            Response.Write("&nbsp;&nbsp;++++");
            Response.Write("Name==>" + c.Name + "\t");
            Response.Write("时间==>" + c.ModifiedOn + "\t");
            Response.Write("<br/>");
        }
    }
    //将一级类别和二级类别显示在页面上,如果使用一个递归,很容易实现无限级分类(你懂的)。
    

     

     

     

    //获取单个ColumnCat对象。
    public ColumnCat SelectColumnCat(int columnCatId)
    {
        using (IDbConnection conn = OpenConnection())
        {
            const string query = "select * from ColumnCat where Id=@id";
            return conn.Query<ColumnCat>(query, new { id=columnCatId})
                            .SingleOrDefault<ColumnCat>();
        }
    }
    

     

    这里我们传递了一个参数给Query方法,参数可以是任何对象,其属性在查询中与sql的参数匹配,由于Query总是返回一个集合,我们只需调用SingleOrDefault方法,因为我们知道总是返回0或1行.

     

    //Dapper也可以加载填充嵌套对象,考虑这样一种情形,考虑到新闻的类别属性,返回类别对象,
    //我们创建一个Column的类
    public class Column
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime ModifiedDate { get; set; }
        public ColumnCat ColumnCat { get; set; }
    }
    

     

     

     

    //接下来我们来填充我们的业务对象。
    public IList<Column> SelectColumnsWithColumnCat()
    {
        using (IDbConnection conn = OpenConnection())
        {
            const string query = "select c.Id,c.Name,c.ModifiedDate,c.ColumnCatid
            ,cat.id,cat.[Name],cat.ModifiedOn,cat.Parentid from [Column] as c
            left outer join ColumnCat as cat on c.ColumnCatid=cat.id";
            return conn.Query<Column, ColumnCat, Column>(query
                   , (column, columncat) => { column.ColumnCat = columncat; return column; }
                   , null, null, false, "Id", null, null).ToList<Column>();
        }
    }
    

     

    注:1,在填充嵌套对象的时候,只好执行ToList<>方法,否则回报ExecuteReader 要求已打开且可用的连接。连接的当前状态为已关闭,而单个对象不会报错,估计是using结束后关闭了连接,而嵌套对象在map的时候又执行了ExecuteReader,只好在using结束之前返回list集合。
    2,嵌套对象的参数是比较多的,主要是前两个参数,其它参数没用可以设置为null,不过在4.0版本可以只写两个参数,其它参数都有默认值。特别要注意的是splitOn,这个参数不能为空,否则会报对象为引用的错误。【splitOn参数的意思是读取第二个对象的的分割列,从哪个列起开始读取第二个对象,如果表里的自增长列都为Id,可以设置这个参数为”Id”】.

     

    Execute方法:
    正如Query方法是检索数据的,Execute方法不会检索数据,它与Query方法非常相似,但它总返回总数(受影响的行数),而不是一个对象集合【如:insert update和delete】.

     

    //接下来向数据库里添加一个类别
    public int InsertColumnCat(ColumnCat cat)
    {
        using (IDbConnection conn = OpenConnection())
        {
            const string query = "insert into ColumnCat([name],ModifiedOn,Parentid)
            values (@name,@ModifiedOn,@Parentid)";
            int row = conn.Execute(query,cat);
            //更新对象的Id为数据库里新增的Id,假如增加之后不需要获得新增的对象,
            //只需将对象添加到数据库里,可以将下面的一行注释掉。
            SetIdentity(conn,id=>cat.Id=id,"id","ColumnCat");    
            return row;
    
        }
    }

     

     

     

    public void SetIdentity(IDbConnection conn, Action<int> setId,string primarykey
                              ,string tableName)
    {
        if (string.IsNullOrEmpty(primarykey)) primarykey = "id";
        if (string.IsNullOrEmpty(tableName))
        {
            throw new ArgumentException("tableName参数不能为空,为查询的表名");
        }
        string query = string.Format("SELECT max({0}) as Id FROM {1}", primarykey
                             , tableName);
        NewId identity = conn.Query<NewId>(query, null).Single<NewId>();
        setId(identity.Id);
    }
    
    public class NewId
    {
        public int Id { get; set; }
    }

     

    由于Dapper是通过类的属性自动绑定的,所以增加了NewId类来获取增加对象后的Id,本来打算使用@@identity,Net3.5下使用总是报错,只好使用Max函数获取。当然如果不需要获得更新后的对象的ID,可以不使用SetIdentity,这个函数通用。

     

    //编译Dapper源码生成的是Net4.0下使用的,可以借助Net4.0新增的dynamic动态类型,
    //SetIdentity的实现将非常方便。如下:
    public void SetIdentity<T>(IDbConnection conn, Action<int> setId)
    {
        dynamic identity = connection.Query("SELECT @@IDENTITY AS Id").Single();
        T newId = (T)identity.Id;
        setId(newId);
    }

     

     

     

    //更新一个类别:
    public int UpdateColumnCat(ColumnCat cat)
    {
        using (IDbConnection conn = OpenConnection())
        {
            const string query = "update ColumnCat set name=@Name
                              ,ModifiedOn=@ModifiedOn,Parentid=@Parentid where Id=@id";
            return conn.Execute(query,cat);
        }
    }

     

     

     

    //删除一个类别:
    public int DeleteColumnCat(ColumnCat cat)
    {
        using (IDbConnection conn = OpenConnection())
        {
            const string query = "delete from ColumnCat where id=@id";
            return conn.Execute(query, cat);
        }
    }

     

    下面介绍一下Dapper的高级用法

     

    //Dapper对事务处理的例子,如删除类别的同时删除类别下的所有新闻。或者删除产品的同时,
    //删除产品图片表里关联的所有图片。
    public int DeleteColumnCatAndColumn(ColumnCat cat)
    {
        using (IDbConnection conn = OpenConnection())
        {
            const string deleteColumn = "delete from [Column] where ColumnCatid=@catid";
            const string deleteColumnCat = "delete from ColumnCat where id=@Id";
    
            IDbTransaction transaction = conn.BeginTransaction();
            int row=conn.Execute(deleteColumn, new { catid =cat.Id},transaction,null,null);
            row += conn.Execute(deleteColumnCat, new { id=cat.Id},transaction,null,null);
            transaction.Commit();
            return row;
        }
    }
    
    
    from: http://www.cnblogs.com/abc8023/p/3425500.html
    展开全文
  • 什么是web框架
  • 下面为大家简单的介绍一下Web框架基本内容,希望对大家有帮助。 Web框架(Web framework)或者叫做Web应用框架(Web application framework),是用于进行Web开发的一套软件架构。大多数的Web框架提供了一套开发和部署...
  • 本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注,...现在Android上的图片加载框架非常成熟,从最早的老牌图片加载框架UniversalImageLoader,到后来Google推出的Volley,再到后
  • c++基本框架

    千次阅读 2018-09-27 09:48:47
     我们接下来来了解一下c++程序的基本框架: 1、头文件:可以认为头文件是你在调用函数时的一个桥梁。c++的程序是由一个又一个的函数组成的,比如说刚刚这个程序里 就可以说包含了两个函数(其中一个函数包含在另一...
  • 什么是关键字驱动框架

    万次阅读 2018-03-19 20:37:15
    什么是关键字驱动框架? 关键字驱动框架是一种功能自动化测试框架,它也被称为表格驱动测试或者基于动作字的测试。关键字驱动的框架基本工作是将测试用例分成四个不同的部分。首先是测试步骤(Test Step),二是...
  • HTML5页面的基本框架结构

    千次阅读 2017-09-28 20:43:37
    生成页面的基本框架主要还是在head标签中增加一些基本的标签 1.<title></title>标签 <title>标签顾名思义,为标题,名字的意思,也就是设置网页在显示栏显示的标题。 2.<meta charset="UTF-...
  • 什么是框架
  • 问题一:什么是框架框架有啥用咧? 框架,即baiframework。指的是实现了某应用领域通用完备功能的底层服务。使用这种框架的编程人员可以在一个通用功能已经实现的基础上开始具体的系统开发。框架提供了所有应用...
  • 手游基本框架的介绍

    千次阅读 2015-04-20 14:25:26
    本文是看到《乐元素CTO凌聪访谈:游戏引擎技术选型之王道》这篇文章后,我觉得还是挺有道理的,其他也说出了一些手游的基本框架,对于小白来说,还是挺有概念价值的。但是说到实际,概念归概念,到最后能写出代码才...
  • 什么是前端框架与后端框架

    万次阅读 2017-05-22 10:11:40
    什么是框架框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。
  • 前端框架MVVM是什么(整理)

    千次阅读 多人点赞 2020-08-06 06:25:42
    二、MVVM百度百科 三、前后端分手大师——MVVM 模式(转) 简而言之 组成部分 没有什么是一个栗子不能解决的 四、不要听吹牛逼什么前端MVVM框架就是好,其实都是一帮没学好分层设计的搞出来的,让你彻底看清前端...
  • c++的基本框架

    万次阅读 2017-05-06 19:29:06
     我们接下来来了解一下c++程序的基本框架: 1、头文件:可以认为头文件是你在调用函数时的一个桥梁。c++的程序是由一个又一个的函数组成的,比如说刚刚这个程序里 就可以说包含了两个函数(其中一个函数包含在另...
  • 什么是web框架

    千次阅读 2017-09-11 14:37:44
    Web 应用框架,或者简单的说是“Web 框架”,其实是建立 web 应用的一种方式。从简单的博客系统到复杂的富 AJAX 应用,web 上每个页面都是通过写代码来生成的。我发现很多人都热衷于学习 web 框架技术,例如 Flask ...
  • 聚宽量化交易策略基本框架

    千次阅读 2019-02-19 19:57:05
    策略编写的基本框架及其实现 回测的含义及其实现 初步学习解决代码错误 周期循环的开始时间 自测与自学 通过前文对量化交易有了一个基本认识之后,我们开始学习做量化交易。毕竟就像学游泳,有些东西讲是讲不懂,做...
  • 什么是 web 框架

    千次阅读 2018-04-22 11:46:42
    什么是 web 框架? Web 应用框架,或者简单的说是“Web 框架”,其实是建立 web 应用的一种方式。从简单的博客系统到复杂的富 AJAX 应用,web 上每个页面都是通过写代码来生成的。我发现很多人都热衷于学习 web ...
  • Fork/Join框架基本使用

    万次阅读 多人点赞 2018-08-06 09:56:42
    1. 概述 ava.util.concurrent.ForkJoinPool由Java大师Doug Lea主持...本文中对Fork/Join框架的讲解,基于JDK1.8+中的Fork/Join框架实现,参考的Fork/Join框架主要源代码也基于JDK1.8+。 这几篇文章将试图解释Fork/...
  • 什么是 Web 框架

    千次阅读 2014-03-06 13:02:15
    我发现很多人都热衷于学习 web 框架技术,例如 Flask 或这 Django 之类的,但是很多人并不理解什么是 web 框架,或者它们是如何工作的。这篇文章中,我将探索反复被忽略的 web 框架基础的话题。阅读完这篇文章,你
  • bootstrap前端框架的简单基本使用

    千次阅读 2017-07-08 12:21:09
    一、框架的导入及使用方法导入框架:需要在html代码最前方加上如下代码:<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.1/css/bootstrap.min.css"/>同时,为了使用该...
  • Java是世界第一编程语言,这已经达成共识,是毋庸置疑的真理。框架是程序员们必学的知识点,而且是十分重要的应用。在Java学习中框架是很重要的,...什么是Java框架? 所谓的Java框架,简单理解是一个可复用的设计构...
  • 什么是RMI,为什么要使用RMI框架

    千次阅读 2019-06-27 09:04:38
    什么是RMI,为什么要使用RMI框架?】 大家好,我是IT修真院深圳分院第10期的JAVA学员,一枚正直纯洁善良的java程序员。 今天给大家分享一下,修真院官网Java任务8,深度思考中的知识点—什么是RMI,为什么要使用...
  • 前端框架MVVM是什么(整理)

    千次阅读 2018-11-05 08:32:00
    前端框架MVVM是什么(整理) 一、总结 一句话总结:vm层(视图模型层)通过接口从后台m层(model层)请求数据,vm层继而和v(view层)实现数据的双向绑定。   1、我大前端应该不应该做复杂的数据处理的工作? ...
  • 但是闲暇时间过来阅览发现该系列还是有许多瑕疵,主要是该系列太偏重重点的讲解了,而忽略了一些基本知识点的详细分析,所以这里反过来重新查漏补缺继续完善该系列文章。   Android Binder是Android高级进阶必须...
  • 简介基本含义 Spring框架主要降低程序的耦合性,耦合性的意思为实现接口和实现类之间的...在学习了三个框架之后Struts2,Hibernate框架分别是对视图层和直流层的操作,而Spring框架负责将两个框架内容进行配置。...
  • 小疯手把手带你整合SpringMVC+Spring+MyBatis三大框架,俗称SSM,用它完全代替传统的SSH框架,把它们最优雅的一面发挥出来。整合配置结束后,会有一个应用实例“图书管理系统”带给大家,希望能快速上手这个框架
  • 这篇文章主要讲了electron应用的基本架构,并对之前下载的应用进行分析electron应用的基本架构在electron中,主要有两类进程。一类是主进程main,还有一类是渲染器进程renderer。主进程只有一个,负责对整个应用的...
  • 框架千变万化,而这些通用的底层知识,却是几乎不变的,了解了这些知识,可以帮助我们更快着学习一门知识,更加懂得计算机的运行机制。当然,在面试中也经常会被问到,特别是对于应届生,对于春秋招,也可以看看我前...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 122,432
精华内容 48,972
关键字:

内容的基本框架是什么意思