【问题标题】:Algorithm for adjustment of image levels调整图像级别的算法
【发布时间】:2017-01-23 10:02:55
【问题描述】:

我需要在 C++ 中实现用于调整图像级别的算法,该算法类似于 Photoshop 或 GIMP 中的级别功能。 IE。输入是:要调整的彩色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);

【问题讨论】:

  • 请向我们展示您到目前为止所做的尝试。首先,您应该熟悉如何 图像的组织方式(RGB 通道)以及可以对它们执行的基本操作。 Stack Overflow 不是代码编写服务,但如果您至少尝试自己解决问题,人们愿意帮助您。请阅读How to create a Minimal, Complete, and Verifiable exampleHow do I ask a good question?。然后,更新并改进您的问题
  • 我熟悉图像表示、使用 OpenCV 加载图像、操作图像通道等。这不是一个问题。问题是图像转换算法。我不是要求为我编写任何代码。相反,我要求帮助我查找有关算法的信息。有了它,我就可以自己编写代码了。
  • 我已经用我现在的代码更新了帖子。代码背后的想法很简单,它计算查找表并将其应用于图像。但是图像被覆盖了,而不是我在同一图像上使用 GIMP 获得相同的输入值。所以我试图理解我做错了什么,可能整个我当前的实现都是基于如何计算查找表的错误想法,所以这就是为什么我要询问正确的算法,而不是代码(即它的实现)。

标签: c++ algorithm image-processing


【解决方案1】:

Photoshop 色阶调整的伪代码

首先,计算用于中间色调调整的伽马校正值(如果需要)。下面粗略地模拟了 Photoshop 的技术,将 9.99-1.00 用于中间调值 0-128,将 1.00-0.01 用于 128-255。

应用伽马校正:

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,如果中间色调

【讨论】:

    【解决方案2】:

    忽略中间调/Gamma,Levels函数是一个简单的线性缩放。

    首先对所有输入值进行线性缩放,使所有小于或等于“黑点”的值都设置为 0,所有大于或等于白点的值都设置为 255。 然后将所有值从 0/255 线性缩放到输出范围。

    对于中点,这取决于您的实际意思。 在 GIMP 中,有一个 Gamma 值。 Gamma 值是输入值的简单指数(在限制为黑/白点之后)。 对于 Gamma == 1,值不会更改。 对于 gamma

    【讨论】:

      猜你喜欢
      • 2011-03-20
      • 1970-01-01
      • 2014-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-12
      相关资源
      最近更新 更多