c++ 图像电平调整算法

vmdwslir  于 2023-07-01  发布在  其他
关注(0)|答案(3)|浏览(137)

我需要在C++中实现调整图像级别的算法,该算法类似于Photoshop或GIMP中的级别功能。即,输入为:色彩RGB图像要调整,调整边点、黑点、中间调点、输出自/到值。但我还没有找到任何关于如何执行此调整的信息。可能有人推荐我学习算法描述或资料。
到目前为止,我自己想出了以下代码,但它没有给予预期的结果,类似于我所看到的,例如在GIMP中,图像变得太亮。下面是我当前的代码片段:

const int normalBlackPoint = 0;
const int normalMidtonePoint = 127;
const int normalWhitePoint = 255;
const double normalLowRange = normalMidtonePoint - normalBlackPoint + 1;
const double normalHighRange = normalWhitePoint - normalMidtonePoint;

int blackPoint = 53;
int midtonePoint = 110;
int whitePoint = 168;
int outputFrom = 0;
int outputTo = 255;

double outputRange = outputTo - outputFrom + 1;
double lowRange = midtonePoint - blackPoint + 1;
double highRange = whitePoint - midtonePoint;
double fullRange = whitePoint - blackPoint + 1;
double lowPart = lowRange / fullRange; 
double highPart = highRange / fullRange; 

int dim(256);
cv::Mat lut(1, &dim, CV_8U);
for(int i = 0; i < 256; ++i)
{
    double p = i > normalMidtonePoint
        ? (static_cast<double>(i - normalMidtonePoint) / normalHighRange) * highRange * highPart + lowPart
        : (static_cast<double>(i + 1) / normalLowRange) * lowRange * lowPart;
    int v = static_cast<int>(outputRange * p ) + outputFrom - 1;
    if(v < 0) v = 0;
    else if(v > 255) v = 255;
    lut.at<uchar>(i) = v;
}

....

    cv::Mat sourceImage = cv::imread(inputFileName, CV_LOAD_IMAGE_COLOR);
    if(!sourceImage.data)
    {
        std::cerr << "Error: couldn't load image " << inputFileName << "." << std::endl;
        continue;
    }

#if 0       
    const int forwardConversion = CV_BGR2YUV;
    const int reverseConversion = CV_YUV2BGR;
#else
    const int forwardConversion = CV_BGR2Lab;
    const int reverseConversion = CV_Lab2BGR;
#endif

    cv::Mat convertedImage;
    cv::cvtColor(sourceImage, convertedImage, forwardConversion);

    // Extract the L channel
    std::vector<cv::Mat> convertedPlanes(3);
    cv::split(convertedImage, convertedPlanes);

    cv::LUT(convertedPlanes[0], lut, convertedPlanes[0]);

    //dst.copyTo(convertedPlanes[0]);
    cv::merge(convertedPlanes, convertedImage);

    cv::Mat resImage;
    cv::cvtColor(convertedImage, resImage, reverseConversion);
    cv::imwrite(outputFileName, resImage);
rkttyhzu

rkttyhzu1#

Photoshop色阶调整伪代码

首先,计算要用于中间色调调整的Gamma校正值(如果需要)。以下内容大致模拟了Photoshop的技术,该技术对中间色调值0-128应用gamma 9.99-1.00,对128-255应用gamma 1.00-0.01。

应用伽玛校正:

Gamma = 1
MidtoneNormal = Midtones / 255
If Midtones < 128 Then
    MidtoneNormal = MidtoneNormal * 2
    Gamma = 1 + ( 9 * ( 1 - MidtoneNormal ) )
    Gamma = Min( Gamma, 9.99 )
Else If Midtones > 128 Then
    MidtoneNormal = ( MidtoneNormal * 2 ) - 1
    Gamma = 1 - MidtoneNormal
    Gamma = Max( Gamma, 0.01 )
End If
GammaCorrection = 1 / Gamma

然后,对于每个像素的每个通道值R、G、B(0-255),按顺序执行以下操作。

应用输入电平:

ChannelValue = 255 * ( ( ChannelValue - ShadowValue ) / 
    ( HighlightValue - ShadowValue ) )

应用中间调:

If Midtones <> 128 Then
    ChannelValue = 255 * ( Pow( ( ChannelValue / 255 ), GammaCorrection ) )
End If

应用输出电平:

ChannelValue = ( ChannelValue / 255 ) *
    ( OutHighlightValue - OutShadowValue ) + OutShadowValue

地点:

  • 所有通道和调整参数值均为整数,包括0-255
  • Shadow/Midtone/HighlightValue是输入调整值(默认值为0、128、255)
  • OutShadow/HighlightValue是输出调整值(默认值为0、255)
  • 你应该优化事情,并确保值保持在界限内(如0-255为每个通道)

为了更准确地模拟Photoshop,如果中间色调< 128,则可以使用非线性插值曲线。Photoshop默认情况下也会去除0.1%的最暗和最亮值。

ws51t4hk

ws51t4hk2#

忽略中间色调/Gamma,Levels函数是一个简单的线性缩放。
所有输入值首先被线性缩放,使得小于或等于“黑点”的所有值被设置为0,并且大于或等于白色的所有值被设置为255。然后,所有值从0/255线性缩放到输出范围。
对于中点-这取决于你实际上是什么意思。在GIMP中,有一个Gamma值。Gamma值是输入值的简单指数(在限制为黑色/白色点之后)。对于Gamma == 1,值不会更改。对于gamma < 1,值变暗。

svmlkihl

svmlkihl3#

感谢伪代码在伪代码中,确切地说是,MidtoneNormal = Midtones / 255
是现有强度的平均值还是各个像素的强度值。
并且在ChannelValue中= 255 *((ChannelValue-ShadowValue)/(HighlightValue-ShadowValue))
什么是HighlightValue和ShadowValue?
它们是通道中的最高和最低强度值(不一定是255和0)吗?

相关问题