我想实现类似于色调曲线的效果。
我理解这张图表显示了当前色调值与新色调值之间的关系,例如: 如果我们在左边看到第一个点 - 每个等于0的r、g和b都将转换为64, 或每个大于224的值都将转换为0等。
所以我尝试将图像的每个像素值更改为新值。
为了测试目的,我简化了曲线:
这是我的代码:
//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](https://istack.dev59.com/v4VSK.webp)
![enter image description here](https://istack.dev59.com/Gp11w.webp)
感谢@ACCurrent的评论,发现计算中的错误(代码和图像已更新),但仍然不明白为什么只处理了图片的3/4部分。
不确定为什么会出现“噪点”,希望是由于曲线不平滑造成的。
看起来有避免使用“.at”操作的方法。
更新1:
原始图片:
![enter image description here](https://istack.dev59.com/E8kXK.webp)
.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。所以会有很多饱和发生。 - ACCurrentat
函数不会很慢。你可以毫无问题地使用它。 - Mikicout << originalMat.type();
。 - Miki{
符号,谢谢。已更新问题。问题仍然存在。originalMat.type()
等于 24。 - Siarhei