OpenCV C++实现Sepia滤镜时图像变绿的原因排查
棕褐色滤镜失效导致图像全绿的原因与修复方案
问题描述
尝试使用OpenCV和C++为图像应用Sepia棕褐色滤镜,但结果不符合预期,图像几乎全变成绿色。相关代码如下:
Mat src = imread("/Users/nithin/Desktop/neu/CV/images/curry.jpeg"); if (src.empty()) { cout << "Could not open or find the image." << endl; return -1; } // Create a new Mat to store the sepia-toned image Mat sepiaToned = src.clone(); // Iterate through each pixel for (int y = 0; y < src.rows; y++) { for (int x = 0; x < src.cols; x++) { Vec3b pixel = src.at<Vec3b>(y, x); // Apply sepia tone filter float blue = pixel[0]; float green = pixel[1]; float red = pixel[2]; float newR = 0.393 * red + 0.349 * green + 0.272 * blue; float newG = 0.769 * red + 0.686 * green + 0.534 * blue; float newB = 0.189 * red + 0.168 * green + 0.131 * blue; // Update pixel values in the new Mat sepiaToned.at<Vec3b>(y, x) = Vec3b(static_cast<uchar>(newB), static_cast<uchar>(newG), static_cast<uchar>(newR)); } } // Display the original and sepia-toned images imshow("Original Image", src); imshow("Sepia-Toned Image", sepiaToned); waitKey(0); return 0;
问题原因
- 通道数值溢出未处理:棕褐色滤镜的计算公式会让绿色通道(
newG)的计算结果极易超过uchar类型的最大值255。例如原像素RGB值均为255时,newG的计算结果约为507,直接用static_cast<uchar>转换会导致数值溢出,变成模256的异常值,最终让图像呈现全绿。 - 错误的类型转换方式:
static_cast不会处理超出范围的数值,只会直接截断,而OpenCV提供的saturate_cast可以自动将数值钳制在目标类型的合法范围内(0-255 for uchar),避免溢出问题。
修复方案
将static_cast<uchar>替换为cv::saturate_cast<uchar>,确保计算后的通道值被正确钳制在0-255之间。修正后的代码如下:
Mat src = imread("/Users/nithin/Desktop/neu/CV/images/curry.jpeg"); if (src.empty()) { cout << "Could not open or find the image." << endl; return -1; } Mat sepiaToned = src.clone(); for (int y = 0; y < src.rows; y++) { for (int x = 0; x < src.cols; x++) { Vec3b pixel = src.at<Vec3b>(y, x); float blue = pixel[0]; float green = pixel[1]; float red = pixel[2]; float newR = 0.393 * red + 0.349 * green + 0.272 * blue; float newG = 0.769 * red + 0.686 * green + 0.534 * blue; float newB = 0.189 * red + 0.168 * green + 0.131 * blue; // 使用saturate_cast处理数值溢出 sepiaToned.at<Vec3b>(y, x) = Vec3b( cv::saturate_cast<uchar>(newB), cv::saturate_cast<uchar>(newG), cv::saturate_cast<uchar>(newR) ); } } imshow("Original Image", src); imshow("Sepia-Toned Image", sepiaToned); waitKey(0); return 0;
也可以手动对数值进行钳制,再用static_cast转换,效果一致:
newR = max(0.0f, min(newR, 255.0f)); newG = max(0.0f, min(newG, 255.0f)); newB = max(0.0f, min(newB, 255.0f));
内容的提问来源于stack exchange,提问作者nithin krishna
相关产品推荐
相关产品推荐

