自己编码使用去色、曲线、色阶算法实现照片怀旧特效。

  天下文章一大抄,看你会抄不会抄,这个算法的初步雏形其实很简单,很多傻瓜级的软件业提供了相应的一键功能,比如美图秀秀。其实这就是个简单的调色功能,实现的方式五花八门,没有一个固定的标准,我们下面仅以几个开源的软件中的算法为例来说明实现过程。

      第一的参考算法是来自Paint.net的,在专业的软件中,这个功能的英文一般称之为Sepia,在Paint.net中,这个算法实现的主要代码如下:

this.desaturate = new UnaryPixelOps.Desaturate();
this.levels = new UnaryPixelOps.Level(
                ColorBgra.Black, 
                ColorBgra.White,
                new float[] { 1.2f, 1.0f, 0.8f },
                ColorBgra.Black,
                ColorBgra.White);

即先去色,然后再执行色阶命令,似乎很简单,而我们先看看效果。

                        原图 

                       Paint.net的效果

                     美图怀旧特效的结果

                        原图 

                       Paint.net的效果

                     美图怀旧特效的结果

  从效果上比较接近的,这里和美图比较,并不是说美图就是行业标准,只是做个参照而已,我这里主要说说Paint.net这个代码的简易实现(并不是照抄其代码,实际上我根本没看Paint.net具体的实现代码,而只看其实现的思路)。

     第一步是个去色,去色的算法有N多种,我们这里以业界老大Adobe Photoshop提供的算法为标准实现,主要C++代码如下:

void __stdcall Desaturate(unsigned char * Src , int Width, int Height ,int Stride )
{
    int X,Y, Max, Min, Value;
    unsigned char * Pointer;
    for (Y = 0; Y < Height; Y++)
    {
        Pointer = Src + Y * Stride;
        for (X = 0; X < Width; X++)
        {
            if (*Pointer >= *(Pointer + 1))     //取R/G/B各分量的最大和最小值的平均值
            {
                Max = *Pointer;
                Min = *(Pointer + 1);
            }
            else
            {
                Max = *(Pointer + 1);
                Min = *Pointer;
            }
            if (*(Pointer + 2) > Max)
                Max = *(Pointer + 2);
            else if (*(Pointer + 2) < Min)
                Min = *(Pointer + 2);
            Value =( Max + Min )>>1;
            *Pointer++ =Value;
            *Pointer++ =Value;
            *Pointer++ =Value;
        }
    }
}

可见PS的去色算法的原理性实现还是很简单的,就是取RGB通道最大值和最小值的平均值,这相当于在色相饱和度效果中的饱和度取0的效果。

     所谓色阶指令,别看PS的Level界面做的很复杂,有N多输入参数,其实内部也没啥复杂的技术,简单的讲就是通过哪些参数计算出一个隐射表,最终都是通过Curve指令来实现的,所以在GIMP下这两个指令的参数可以在不同界面之间相互转换。下面先给出通过那些参数计算隐射表的过程:

void  GetLevelTable(unsigned char * Table, unsigned char InputLeftLimit, unsigned char InputMiddle, unsigned char InputRightLimit, unsigned char OutputLeftLimit , unsigned char OutputRightLimit)
{
    if (InputLeftLimit > 253) InputLeftLimit = 253;
    if (InputLeftLimit < 0)    InputLeftLimit = 0;
    if (InputRightLimit > 255)InputRightLimit = 255;
    if (InputRightLimit < 2) InputRightLimit = 2;
    if (InputMiddle > 254)InputMiddle = 254;
    if (InputMiddle < 1)InputMiddle = 1;
    if (InputMiddle > InputRightLimit)InputMiddle = InputRightLimit - 1;
    if (InputMiddle < InputLeftLimit)InputMiddle = InputLeftLimit + 1;
    if (OutputLeftLimit < 0)OutputLeftLimit = 0;
    if (OutputLeftLimit > 255)OutputLeftLimit = 255;
    if (OutputRightLimit < 0)OutputRightLimit = 0;
    if (OutputRightLimit > 255)OutputRightLimit = 255;

    for (int Index = 0; Index <= 255; Index++)
    {
        double Temp = Index - InputLeftLimit;
        if (Temp < 0) 
        {
            Temp = OutputLeftLimit;
        }
        else if (Temp + InputLeftLimit > InputRightLimit)
        {
            Temp = OutputRightLimit;
        }
        else 
        {
            double Gamma = log(0.5) / log((double)(InputMiddle - InputLeftLimit) / (InputRightLimit - InputLeftLimit));
            Temp = OutputLeftLimit + (OutputRightLimit - OutputLeftLimit) * pow((Temp / (InputRightLimit - InputLeftLimit)), Gamma);
        }
        if (Temp > 255)
            Temp = 255;
        else if (Temp < 0)
            Temp = 0;
        Table[Index] = Temp;
    }
}

  我们先贴下PS的Level界面:

  我想稍微懂点英语的人对理解上面代码中的参数和这个界面中的那些位置的标签对应应该都没有问题,如果有,请回到初中课堂。 

     这里重点关注下上图中有提示文字“调整中间调输入色阶"一项,PS的这一栏的输入范围是9.9-0.01,而我上述代码中对应的范围是1-254,唯一的区别我觉得就是量化等级变得少了,这里的主要算法我记得是模仿的Gimp的。

     有了上述过程,只要在进行一个隐射就OK了,这部分其实就是PS的曲线功能的结果,虽然你看曲线的界面那么复杂,其实都是一些控制而已。

void __stdcall Curve(unsigned char * Src , int Width, int Height , int Stride ,unsigned char * TableB,unsigned char * TableG,unsigned char * TableR)
{
    int X,Y;
    int ByteCount = Stride / Width;
    unsigned char * Pointer;
    for (Y = 0; Y < Height; Y++)
    {
        Pointer = Src + Y * Stride;
        for (X = 0; X < Width; X++)
        {
            *Pointer++ = TableB[*Pointer];
            *Pointer++ = TableG[*Pointer];
            *Pointer++ = TableR[*Pointer];
        }
    }
}

最后给出Level命令的代码:

void __stdcall Level(unsigned char * Src , int Width, int Height ,int Stride , Channel DestChannel, unsigned char InputLeftLimit, unsigned char InputMiddle, unsigned char InputRightLimit, unsigned char OutputLeftLimit , unsigned char OutputRightLimit)
{
    unsigned char * Table = (unsigned char *) malloc ( 256 * sizeof (unsigned char));
    unsigned char * LinearTable = (unsigned char *) malloc ( 256 * sizeof (unsigned char));
    for (int X=0;X<256;X++)    LinearTable[X] = X; 
    GetLevelTable(Table, InputLeftLimit,InputMiddle,InputRightLimit,OutputLeftLimit,OutputRightLimit);
    if (DestChannel == RGB)
        Curve(Src,Width,Height,Stride,Table,Table,Table);
    else if (DestChannel == Blue)
        Curve(Src,Width,Height,Stride,Table,LinearTable,LinearTable);
    else if (DestChannel == Green)
        Curve(Src,Width,Height,Stride,LinearTable,Table,LinearTable);
    else if (DestChannel == Red)
        Curve(Src,Width,Height,Stride,LinearTable,LinearTable,Table);
    free(Table);
    free(LinearTable);
}

对应上述Paint.net的level指令,我们把我们的调用形式更给为:

Level(Dest, Width, Height, Stride, Channel.Blue, 0, 152, 255, 0, 255);
Level(Dest, Width, Height, Stride, Channel.Red, 0, 101, 255, 0, 255);

 就OK了,具体的调用即效果可见后面的附件。

     第二中参考算法来自于ImageJ软件,JAVA版本的图像处理包。其所谓的Sepia的命令只能针对8位灰度图,其实这个就印证了上述的Desaturate过程,并且Sepia出现在其LookUp Tables命令组内,这也就和上述描述想对应:level指令也是一种简单的映射而已,我们这里贴出ImageJ的相关隐射表的数据:

 byte[] Table = {
                0,0,0, 
                43,28,4, 
                57,35,5, 
                65,35,6, 
                66,36,7, 
                67,37,8, 
                68,38,9, 
                69,39,10, 
                70,40,11, 
                71,41,12, 
                72,42,13, 
                73,43,14, 
                74,44,15, 
                75,45,16, 
                76,46,17, 
                77,47,18, 
                78,48,19, 
                79,49,20, 
                80,50,21, 
                81,51,22, 
                82,52,23, 
                83,53,24, 
                83,53,24, 
                84,54,25, 
                85,55,26, 
                86,56,27, 
                87,57,28, 
                88,58,29, 
                89,59,30, 
                90,60,31, 
                91,61,32, 
                92,62,33, 
                93,63,34, 
                94,64,35, 
                95,65,36, 
                96,66,37, 
                97,67,38, 
                98,68,39, 
                99,69,40, 
                100,70,41, 
                101,71,42, 
                102,72,43, 
                103,73,44, 
                104,74,45, 
                105,75,46, 
                106,76,47, 
                107,77,48, 
                107,77,48, 
                108,78,49, 
                109,79,50, 
                110,80,51, 
                111,81,52, 
                112,82,53, 
                113,83,54, 
                114,84,55, 
                115,85,56, 
                116,86,57, 
                117,87,58, 
                118,88,59, 
                119,89,60, 
                120,90,61, 
                121,91,62, 
                122,92,63, 
                123,93,64, 
                124,94,65, 
                125,95,66, 
                125,95,66, 
                126,96,67, 
                127,97,68, 
                128,98,69, 
                129,99,70, 
                130,100,71, 
                131,101,72, 
                132,102,73, 
                133,103,74, 
                134,104,75, 
                135,105,76, 
                136,106,77, 
                137,107,78, 
                138,108,79, 
                139,109,80, 
                140,110,81, 
                141,111,82, 
                142,112,83, 
                143,113,84, 
                144,114,85, 
                145,115,86, 
                146,116,87, 
                147,117,88, 
                148,118,89, 
                149,119,90, 
                150,120,91, 
                151,121,92, 
                152,122,93, 
                153,123,94, 
                154,124,95, 
                155,125,96, 
                156,126,97, 
                157,127,98, 
                158,128,99, 
                159,129,100, 
                160,130,101, 
                161,131,102, 
                162,132,103, 
                163,133,104, 
                164,134,105, 
                165,135,106, 
                166,136,107, 
                167,137,108, 
                168,138,109, 
                169,139,110, 
                170,140,111, 
                171,141,112, 
                172,142,113, 
                173,143,114, 
                174,144,115, 
                175,145,116, 
                176,146,117, 
                177,147,118, 
                178,148,119, 
                179,149,120, 
                180,150,121, 
                181,151,122, 
                182,152,123, 
                183,153,124, 
                184,154,125, 
                185,155,126, 
                186,156,127, 
                187,157,128, 
                187,157,128, 
                188,158,129, 
                189,159,130, 
                190,160,131, 
                191,161,132, 
                192,162,133, 
                193,163,134, 
                194,164,135, 
                195,165,136, 
                196,166,137, 
                197,167,138, 
                198,168,139, 
                199,169,140, 
                200,170,141, 
                201,171,142, 
                202,172,143, 
                203,173,144, 
                204,174,145, 
                205,175,146, 
                206,176,147, 
                207,177,148, 
                208,178,149, 
                209,179,150, 
                210,180,151, 
                211,181,152, 
                212,182,153, 
                213,183,154, 
                214,184,155, 
                215,185,156, 
                216,186,157, 
                217,187,158, 
                218,188,159, 
                219,189,160, 
                220,190,161, 
                221,191,162, 
                222,192,163, 
                223,193,164, 
                224,194,165, 
                225,195,166, 
                226,196,167, 
                227,197,168, 
                228,198,169, 
                229,199,170, 
                230,200,171, 
                231,201,172, 
                232,202,173, 
                233,203,174, 
                234,204,175, 
                235,205,176, 
                236,206,177, 
                237,207,178, 
                238,208,179, 
                239,209,180, 
                240,210,181, 
                241,211,182, 
                242,212,183, 
                243,213,184, 
                244,214,185, 
                245,215,186, 
                246,216,187, 
                247,217,188, 
                248,218,189, 
                249,219,190, 
                250,220,191, 
                251,221,192, 
                252,222,193, 
                253,223,194, 
                254,224,195, 
                255,225,196, 
                255,225,196, 
                255,225,196, 
                255,225,196, 
                255,225,196, 
                255,225,197, 
                255,225,197, 
                255,225,197, 
                255,225,197, 
                255,226,198, 
                255,226,198, 
                255,226,198, 
                255,226,198, 
                255,226,198, 
                255,226,199, 
                255,226,199, 
                255,226,199, 
                255,226,199, 
                255,226,199, 
                255,227,200, 
                255,227,200, 
                255,227,200, 
                255,227,200, 
                255,227,200, 
                255,227,201, 
                255,227,201, 
                255,227,201, 
                255,227,201, 
                255,227,201, 
                255,228,202, 
                255,228,202, 
                255,228,202, 
                255,228,202, 
                255,228,202, 
                255,228,202, 
                255,228,203, 
                255,228,203, 
                255,228,203, 
                255,228,203, 
                255,228,203, 
                255,229,204, 
                255,229,204, 
                255,229,204, 
                255,229,204, 
                255,229,204, 
                255,229,204, 
                255,229,205, 
                255,229,205, 
                255,229,205, 
                255,229,205, 
                255,229,205, 
                255,230,205, 
                255,230,205, 
                255,231,205, 
                255,231,209, 
                255,233,214, 
                255,233,217, 
                255,242,233, 
                255,255,255
            };

View Code

  你如果在网络上搜索PS+老照片效果,你会发现这其实只是处理过程中占有比例很小的一部分,但是这一部分却对最终的效果起到了铺垫的作用。也就是说,仅仅通过这一过程,只是获得老照片效果的基础,一个出色的自动老照片滤镜还需要更多的其他处理,比如老照片必然存在一些皱褶,边缘部位很有可能有磨损,图片周边一般比较偏暗等等。这些过程的实现需要较强的编码能力和创造力,在GIMP中存在一个old photo插件,可以实现较为出色的效果,并且这个是个开源的软件,有想开发此类算法的朋友应该去参考下。

    相关程序下载: http://files.cnblogs.com/Imageshop/OldPhoto.rar

*********************************作者: laviewpbt   时间: 2013.12.6   联系QQ:  33184777  转载请保留本行信息************************

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏何俊林

通过GPUImage实现40+种滤镜与实时美颜功能

推荐一个滤镜和美颜功能实现项目,包含40+种滤镜与实时美颜与后处理美颜功能,非常强大。 相机预览模式 示例见:com.seu.magiccamera.activ...

3888
来自专栏人人都是极客

自动驾驶的模型预测控制

我们实施了一个模型预测控制来驱动赛道上的赛车。但是这一次我们没有交叉错误,我们必须自己计算。另外,在连接延迟之上的执行命令之间有100毫秒的延迟。 这篇文章从非...

5064
来自专栏大数据文摘

目标检测必须要OpenCV?10行Python代码也能实现,亲测好用!

本文作者和他的团队构建了一个名为ImageAI 的Python库,集成了现今流行的深度学习框架和计算机视觉库。本文将手把手教你构建自己的第一个目标检测应用,而且...

956
来自专栏机器之心

教程 | 在Cloud ML Engine的TPU上从头训练ResNet

张量处理单元(TPU)是能够大大加快深度学习模型训练速度的硬件加速器。在斯坦福大学进行的独立测试中,在 TPU 上训练的 ResNet-50 模型能够在 Ima...

692
来自专栏CVPy

OpenCV检测篇(一):猫脸检测

OpenCV是时下最流行的基于C++的开源计算机视觉库,它功能丰富,函数众多,从最基本的读写图片,到简单的图像处理,再到更加高级的行人检测、人脸识别、文本识别等...

1.5K3
来自专栏hrscy

Unity地形基础

![Uploading 2016-05-02_20-09-56_318489.png . . .]](http://upload-images.jianshu....

832
来自专栏理论坞

那些你不知道的Ps冷知识③——完结

本条是针对PSCC及以上版本的技巧(在PSCC发布之初本是没有这个功能的,后续的更新中才加上),第一次使用CC时相信很多人在使用路径选择工具时都有一些不适感——...

491
来自专栏跟边禾玩建模

游戏模型建模中使用3DMAX的问答总结

很对小伙伴在进行游戏模型建模中,使用3DMAX都有很多问题。这些问题有一些非常经典,因为很多人都曾遇到过。在此我把这些问题整理出来,希望对于刚接触游戏模型建模的...

1043
来自专栏重庆的技术分享区

Github contribution settings 提交颜色说明(绿的程度)

2214
来自专栏逍遥剑客的游戏开发

MD2关键帧动画

2526

扫码关注云+社区