Photoshop图像亮度/对比度调整

简单介绍一下Photoshop图像亮度/对比度调整的原理:http://www.cnblogs.com/maozefa/archive/2011/12/13/2286891.html

    一、对比度算法公式。

    Photoshop对于对比度增量,是按给定值的正负分别处理的。

    如果用newRGB表示图像像素新的R、G、B分量,RGB表示图像像素R、G、B分量,Threshold为给定的阀值,Contrast为对比度增量,当Contrast大于0时:

         1) newRGB = RGB + (RGB - Threshold) * (1 / (1 - Contrast / 255) - 1)

    其中,当Contrast等于255时(RGB - Threshold) * (1 / (1 - Contrast / 255) - 1)为无限(±),由于RGB最大最小值分别为255和0,因此,只能按Threshold来确定newRGB,即newRGB = RGB >= Threshold? 255 : 0,这实际就是设置图像阀值,图像由最多八种颜色组成,即红、黄、绿、青、蓝、紫及黑与白,在灰度图上也只有最多8条线。

    当Contrast小于0时:

        2) newRGB = RGB + (RGB - Threshold) * Contrast / 255

    其中,当Contrast等于-255时,图像RGB各分量都等于阀值,图像呈全灰色,灰度图上只有1条线,即阀值灰度。

    二、图像亮度调整。本文采用的是最常用的非线性亮度调整(Phoposhop CS3以下版本也是这种亮度调整方式,CS3及以上版本也保留了该亮度调整方式的选项)。

    三、图像亮度/对比度综合调整算法。这个很简单,当亮度、对比度同时调整时,如果对比度大于0,现调整亮度,再调整对比度;当对比度小于0时,则相反,先调整对比度,再调整亮度。

    下面是用BCB2007和GDI+位图数据写的Photoshop图像亮度/对比度调整全部代码,包括例子代码:

 

复制代码
// ---------------------------------------------------------------------------

//  定义ARGB像素结构
typedef union
{
    ARGB Color;
     struct
    {
        BYTE Blue;
        BYTE Green;
        BYTE Red;
        BYTE Alpha;
    };
}ARGBQuad, *PARGBQuad;
// ---------------------------------------------------------------------------
复制代码

 

复制代码
// ---------------------------------------------------------------------------

FORCEINLINE
INT CheckValue(INT value)
{
     return value <=  00 : value >=  255255 : value;
}
// ---------------------------------------------------------------------------

VOID BrightAndContrast(BitmapData *data, INT bright, INT contrast, BYTE threshold)
{
    FLOAT cv = contrast <= - 255? - 1.0f : contrast /  255.0f;
     if (contrast >  0 && contrast <  255)
        cv =  1.0f / ( 1.0f - cv) -  1.0f;

    BYTE values[ 256];
     for (INT i =  0; i <  256; i ++)
    {
        INT v = contrast >  0? CheckValue(i + bright) : i;
         if (contrast >=  255)
            v = v >= threshold?  255 :  0;
         else
            v = CheckValue(v + (INT)((v - threshold) * cv +  0.5f));
        values[i] = contrast <  0? CheckValue(v + bright) : v;
    }

    PARGBQuad p = (PARGBQuad)data->Scan0;
    INT offset = data->Stride - data->Width *  sizeof(ARGBQuad);

     for (UINT y =  0; y < data->Height; y ++, (BYTE*)p += offset)
    {
         for (UINT x =  0; x < data->Width; x ++, p ++)
        {
            p->Blue        = values[p->Blue];
            p->Green    = values[p->Green];
            p->Red        = values[p->Red];
        }
    }
}
// ---------------------------------------------------------------------------

//  锁定GDI+位位图扫描线到data
FORCEINLINE
VOID LockBitmap(Gdiplus::Bitmap *bmp, BitmapData *data)
{
    Gdiplus::Rect r( 00, bmp->GetWidth(), bmp->GetHeight());
    bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite,
        PixelFormat32bppARGB, data);
}
// ---------------------------------------------------------------------------

//  GDI+位图扫描线解锁
FORCEINLINE
VOID UnlockBitmap(Gdiplus::Bitmap *bmp, BitmapData *data)
{
    bmp->UnlockBits(data);
}
// ---------------------------------------------------------------------------

void __fastcall TForm1::Button3Click(TObject *Sender)
{
    Gdiplus::Bitmap *bmp =   new Gdiplus::Bitmap(L " d:\\source.jpg ");
    Gdiplus::Graphics *g =  new Gdiplus::Graphics(Canvas->Handle);
    g->DrawImage(bmp,  00);

    BitmapData data;
    LockBitmap(bmp, &data);
    BrightAndContrast(&data,  0100121);
    UnlockBitmap(bmp, &data);
    g->DrawImage(bmp, data.Width,  0);

    delete g;
    delete bmp;
}
// ---------------------------------------------------------------------------
复制代码

    在亮度/对比度调整函数BrightAndContrast中,首先按前面介绍的原理制造了一个256个元素大小的查找表,然后对图像数据逐像素按R、G、B分量值在查找表中取得调整后的数据,因此处理速度相当快。

    水平有限,错误在所难免,欢迎指正和指导。邮箱地址:maozefa@hotmail.com



非线性模型中对比度增大和阈值Threshold有关:

Contrast >= 0时:

newRGB = RGB + (RGB - Threshold) * (1 / (1 - Contrast / 255) - 1)

Contrast < 0时:

newRGB = RGB + (RGB - Threshold) * Contrast / 255

那么当对比度和亮度同时调整时候呢?

如果对比度大于0,先调整亮度,再调整对比度;当对比度小于0时,则相反,先调整对比度,再调整亮度。

最后一个问题,阈值Threshold到底是什么,其实这个是图片的灰度平均值。

 

实现代码

复制代码
var brightnessContrast = function(__src, __brightness, __contrast){
    __src || error(arguments.callee, IS_UNDEFINED_OR_NULL/* {line} */);
    if(__src.type === "CV_RGBA"){
        var sData = __src.data,
            width = __src.col,
            height = __src.row,
            dst = new Mat(height, width, CV_RGBA),
            dData = dst.data,
            brightness = Math.max(-255, Math.min(255, __brightness || 0)),
            contrast = Math.max(-255, Math.min(255, __contrast || 0));
        
        var gray = cvtColor(__src, CV_RGBA2GRAY),
            allValue = 0,
            gData = gray.data;
        var y, x, c;
        
        for(y = height; y--;){
            for(x = width; x--;){
                allValue += gData[y * width + x];
            }
        }
        
        var r, g, b, offset, gAverage = (allValue / (height * width)) | 0;
        
        for(y = height; y--;){
            for(x = width; x--;){
                offset = (y * width + x) * 4;
                dData[offset] = sData[offset] + brightness; 
                dData[offset + 1] = sData[offset + 1] + brightness; 
                dData[offset + 2] = sData[offset + 2] + brightness; 
            
                if(contrast >= 0){ 
                    for(c = 3; c--;){ 
                        if(dData[offset + c] >= gAverage){ 
                            dData[offset + c] = dData[offset + c] + (255 - gAverage) * contrast / 255; 
                        }else{ 
                            dData[offset + c] = dData[offset + c] - (gAverage * contrast / 255); 
                        } 
                    } 
                }else{
                    dData[offset] = dData[offset] + (dData[offset] - gAverage) * contrast / 255; 
                    dData[offset + 1] = dData[offset + 1] + (dData[offset + 1] - gAverage) * contrast / 255; 
                    dData[offset + 2] = dData[offset + 2] + (dData[offset + 2] - gAverage) * contrast / 255; 
                }
                
                dData[offset + 3] = 255;
            }
        }
    }else{
        error(arguments.callee, UNSPPORT_DATA_TYPE/* {line} */);
    }
    return dst;
};
复制代码

 

效果


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值