解释颜色功能并调整像素值

11

这是我从网络资源中阅读到的定义:

第一个定义是:

中间色调:位于最暗色调(黑色)和最亮色调(白色)之间。对于24位彩色图像,当红色=绿色=蓝色=128时,就会出现中间色调。

另一个定义是:

Tones created by dots between 30% and 70% of coverage

并且

中间色调还指那些未与黑色(阴影)或白色(高光)混合的颜色范围。

从这些定义中我得到的是,像素值为0或255的像素应该调整为128。我的理解正确吗?我不想使用直方图均衡化的方法,因为据我所知,它也用于图像亮度。

我想要执行以下函数,例如,我想在 OpenCV C++ 中执行此函数,但我不知道如何处理Midtones和CYMK值,因为它同时具有RGB和CMYK。

enter image description here

例如:

样本图像

enter image description here

应用上述值后

enter image description here

我想在OpenCV中执行相同的操作。

我只关心结果,是否可以只使用RGB来执行此操作?

编辑

Andrey的答案不错,但仍在等待最佳答案,因为这个答案对于调整其他颜色平衡值的其他图像来说很困难。


我在哪里可以看到你想要在动态中展示的功能示例?请列出任何原型。 - Andrey Smorodov
@AndreySmorodov,我更新了我的问题。 - AHF
@MarkRansom 我只想知道如何实现它,逻辑是我所需要的,这只是颜色游戏,但它超出了我的逻辑 :) - AHF
如果我可以使用RGB或任何OpenCV函数执行相同的功能,那么我就不需要这个控件。 - AHF
我没有,实际上我想在OpenCV中使用这个控件来进行工作。 - AHF
显示剩余2条评论
3个回答

11

我认为在这种情况下,阴影、中间调和高光定义了拖动条值的范围。

  • 阴影 - 精确定位(小范围);
  • 中间调 - 中等调整(中等范围);
  • 高光 - 大幅度调整(广泛范围)。

这使得快速精确地进行颜色校正成为可能。

代码片段:

#include <iostream>
#include <vector>
#include <stdio.h>
#include <functional>
#include <algorithm>
#include <numeric>
#include <cstddef>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;

int val_Cyan_Red=0;
int val_Magenta_Green=0;
int val_Yellow_Blue=0;
Mat result;
Mat Img;

void on_trackbar( int, void* )
{
float SH=0.1; // The scale of trackbar ( depends on ajusting mode Shadows/Midtones/Highlights )

float cr_val=(float)val_Cyan_Red/255.0;
float mg_val=(float)val_Magenta_Green/255.0;
float yb_val=(float)val_Yellow_Blue/255.0;
// Cyan_Red
float R1=0;
float G1=1;
float B1=1;

float R2=1;
float G2=0;
float B2=0;

float DR=(1-cr_val)*R1+(cr_val)*R2-0.5;
float DG=(1-cr_val)*G1+(cr_val)*G2-0.5;
float DB=(1-cr_val)*B1+(cr_val)*B2-0.5;

result=Img+(Scalar(DB,DG,DR)*SH);

// Magenta_Green
 R1=1;
 G1=0;
 B1=1;

 R2=0;
 G2=1;
 B2=0;

 DR=(1-mg_val)*R1+(mg_val)*R2-0.5;
 DG=(1-mg_val)*G1+(mg_val)*G2-0.5;
 DB=(1-mg_val)*B1+(mg_val)*B2-0.5;

result+=(Scalar(DB,DG,DR)*SH);

// Yellow_Blue

 R1=1;
 G1=1;
 B1=0;

 R2=0;
 G2=0;
 B2=1;

 DR=(1-yb_val)*R1+(yb_val)*R2-0.5;
 DG=(1-yb_val)*G1+(yb_val)*G2-0.5;
 DB=(1-yb_val)*B1+(yb_val)*B2-0.5;

result+=(Scalar(DB,DG,DR)*SH);

imshow("Result",result);
waitKey(10);
}

// ---------------------------------
// 
// ---------------------------------
int main( int argc, char** argv )
{
    namedWindow("Image",cv::WINDOW_NORMAL);
    namedWindow("Result");

    Img=imread("D:\\ImagesForTest\\cat2.jpg",1);
    Img.convertTo(Img,CV_32FC1,1.0/255.0);  

   createTrackbar("CyanRed", "Image", &val_Cyan_Red, 255, on_trackbar);
   createTrackbar("MagentaGreen", "Image", &val_Magenta_Green, 255, on_trackbar);
   createTrackbar("YellowBlue", "Image", &val_Yellow_Blue, 255, on_trackbar);

    imshow("Image",Img);
    waitKey(0);
}

对于上述近似的值(零偏移为128),结果如下图所示: enter image description here


在上述函数中,控制首先仅对CMYK中的青色和品红色产生影响,然后才是BGR中的蓝色。因此,我首先将我的图像转换为CMYK,添加青色和品红色,然后再更改为BGR,最后再减去蓝色? - AHF
1
青色 = (1,0,0,0) ; 红色 = (0,1,1,0) 洋红色(0,1,0,0) ; 绿色 (1,0,1,0) 黄色(0,0,1,0) ; 蓝色 (1,1,0,0)。正如您所看到的,每个滚动条都会更改3个值。您需要将RGB转换为CMYK,然后通过从每个滚动条的通道相乘得到的增量来调整值(我猜测)。然后将其转换回RGB。 - Andrey Smorodov
非常感谢,为什么这行代码会显示错误 result+=(Scalar(DB,DG,DR)*SH); - AHF
@AndreySmorodov,您能解释一下您是如何推导出像DR =(1-yb_val)* R1 +(yb_val)* R2-0.5;这样的公式以及SH如何确定它是亮部、阴影等的范围吗?我不太擅长数学... - Arjan Singh
这只是一个交叉淡入淡出),Ax+B(1-x)=Val。如果x=0,则Val将为A,如果x=1,则V将等于B。因此,如果A和B是颜色分量向量,则从0到1改变x将平滑地将结果从A更改为B。 - Andrey Smorodov
显示剩余8条评论

3
中间色调区域是任何图像中的中间阴影区域,几乎位于图像最亮和最暗区域的中间位置,它们不一定要在128左右。在曝光过度的情况下,中间色调区域将比暗或曝光不足的图像高得多。
然而,如果进行直方图均衡化,则中间色调区域将被设置为接近128的值[对于8位图像]。
关于如何获取中间色调区域,我认为您可以从直方图中简单地获取此信息。
1.将图像转换为灰度。 2.获取直方图。 3.进行直方图均衡化。 4.现在,中央强度值(例如在255/3到2*255/3之间)是中间色调。

2
使用OpenCV的split函数将图像分割成红、绿、蓝三个通道。
看起来第二张图中,蓝色和绿色更加突出,而红色受到了抑制。因此,将红色通道除以1.5。
然后使用OpenCV的merge函数重新组合通道。现在,您拥有相同的图像,但是红色比蓝色和绿色要弱,这应该会得到所需的图像。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接