OpenCV程序化调整色调曲线

3

我想实现类似于色调曲线的效果。

我有一组预定义的曲线,需要将其应用于图像。例如: enter image description here

我理解这张图表显示了当前色调值与新色调值之间的关系,例如: 如果我们在左边看到第一个点 - 每个等于0的r、g和b都将转换为64, 或每个大于224的值都将转换为0等。

所以我尝试将图像的每个像素值更改为新值。

为了测试目的,我简化了曲线:

enter image description here

这是我的代码:

//init original image
cv::Mat originalMat = [self cvMatFromUIImage:inputImage];

//out image the same size
cv::Mat outMat      = [self cvMatFromUIImage:inputImage];

//loop throw every row of image
for( int y = 0; y < originalMat.rows; y++ ){
    //loop throw every column of image
   for( int x = 0; x < originalMat.cols; x++ ){
     //loop throw every color channel of image (R,G,B)
     for( int c = 0; c < 3; c++ ){

        if(originalMat.at<cv::Vec3b>(y,x)[c] <= 64)
       outMat.at<cv::Vec3b>(y,x)[c] = 64 + ( originalMat.at<cv::Vec3b>(y,x)[c] ) -
        ( originalMat.at<cv::Vec3b>(y,x)[c] ) * 2    ;

        if((originalMat.at<cv::Vec3b>(y,x)[c] > 64)&&(originalMat.at<cv::Vec3b>(y,x)[c] <= 128))
        outMat.at<cv::Vec3b>(y,x)[c] = (( originalMat.at<cv::Vec3b>(y,x)[c] ) - 64  ) * 4
        ;

        if((originalMat.at<cv::Vec3b>(y,x)[c] > 128))
        outMat.at<cv::Vec3b>(y,x)[c] = ( originalMat.at<cv::Vec3b>(y,x)[c] ) + 128 -
        (( originalMat.at<cv::Vec3b>(y,x)[c] ) - 128)  * 3;

     } //end of r,g,b loop
   } //end of column loop
 } //end of row loop

//send to output
return [self UIImageFromCVMat:outMat];

但是我得到的结果是这样的:enter image description here 由于某种原因,只处理了图片的3/4部分,并且它与我预期的结果不匹配:enter image description here 更新0:
感谢@ACCurrent的评论,发现计算中的错误(代码和图像已更新),但仍然不明白为什么只处理了图片的3/4部分。
不确定为什么会出现“噪点”,希望是由于曲线不平滑造成的。
看起来有避免使用“.at”操作的方法。
更新1:
原始图片:enter image description here

1
避免使用 OpenCV 中的 .at<> 函数,它非常慢。另外,在进行第一次检查时,假设 gaussMat.at<cv::Vec3b>(y,x)[c] 的值为 128。 然后: if((gaussMat.at<cv::Vec3b>(y,x)[c] > 64)&&(gaussMat.at<cv::Vec3b>(y,x)[c] <= 128)) outMat.at<cv::Vec3b>(y,x)[c] = ( gaussMat.at<cv::Vec3b>(y,x)[c] ) - 64 + ( gaussMat.at<cv::Vec3b>(y,x)[c] ) * 4 因此,128-64+128*4 等于 576,远远超过 CV_U8c 的最大值 255。所以会有很多饱和发生。 - ACCurrent
1
你能同时发布原始图片吗?别担心... at 函数不会很慢。你可以毫无问题地使用它。 - Miki
@Miki 原始图像已添加 - Siarhei
在你发布的代码中,for循环中的“{”和“}”存在问题。请更正它们,并检查结果是否仍然不好。另外,请输出 cout << originalMat.type(); - Miki
@Miki 抱歉,编辑代码时错过了 { 符号,谢谢。已更新问题。问题仍然存在。 originalMat.type() 等于 24。 - Siarhei
1个回答

3

你需要使用 Vec4b 访问图像。


originalMat.type() 等于 24

你的 originalMat 的类型是 24,即 CV_8UC4。这意味着该图像有 4 个通道,但你正在使用 Vec3b 访问它,就好像它只有 3 个通道一样。这就解释了为什么大约四分之一的图像没有被修改。

因此,只需将代码中的每个 Vec3b 替换为 Vec4b 即可。


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