saturate_cast函数在OpenCV中的作用是防数据溢出,我们在直接操作像素点的时候,如果数值结果是赋值或者超过了255的话,在图片中是没办法显示的,这就是防数据溢出的作用,那么什么时候会有数据溢出的风险呢,这种情况在图像卷积操作的时候比较常见。 下面我们举个栗子吧: 选择一个3*3的锐化作用的卷积核,设计如下: (0, -1, 0, -1, 5, -1, 0, -1, 0) 分别使用OpenCV的filter2D函数和自己写的Convlution函数实现对一张图片的卷积:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
using namespace std;
using namespace cv;
Mat Kernel_test_3_3 = (Mat_<double>(3,3) <<
0,-1,0,
-1,5,-1,
0,-1,0);
void Convlution(Mat InputImage,Mat OutputImage,Mat kernel)
{
//计算卷积核的半径
int sub_x = kernel.cols/2;
int sub_y = kernel.rows/2;
//遍历图片
for (int image_y=0;image_y<InputImage.rows-2*sub_y;image_y++)
{
for(int image_x=0;image_x<InputImage.cols-2*sub_x;image_x++)
{
int pix_value = 0;
for (int kernel_y = 0;kernel_y<kernel.rows;kernel_y++)
{
for(int kernel_x = 0;kernel_x<kernel.cols;kernel_x++)
{
double weihgt = kernel.at<double>(kernel_y,kernel_x) ;
int value = (int)InputImage.at<uchar>(image_y+kernel_y,image_x+kernel_x);
pix_value +=weihgt*value;
}
}
OutputImage.at<uchar>(image_y+sub_y,image_x+sub_x) = (uchar)pix_value;
//OutputImage.at<uchar>(image_y+sub_y,image_x+sub_x) = saturate_cast<uchar>((int)pix_value);
if ((int)pix_value!=(int)saturate_cast<uchar>((int)pix_value))
{
//cout<<"没有防溢出"<<(int)pix_value<<endl;
//cout<<"防溢出"<<(int)saturate_cast<uchar>((int)pix_value)<<endl;
//cout<<"没有防溢出写入了什么?"<<(int)OutputImage.at<uchar>(image_y+sub_y,image_x+sub_x)<<endl;
//cout<<endl;
}
}
}
}
int main()
{
Mat srcImage = imread("1.jpg",0);
namedWindow("srcImage", WINDOW_AUTOSIZE);
imshow("原图", srcImage);
//filter2D卷积
Mat dstImage_oprncv(srcImage.rows,srcImage.cols,CV_8UC1,Scalar(0));;
filter2D(srcImage,dstImage_oprncv,srcImage.depth(),Kernel_test_3_3);
imshow("filter2D卷积图",dstImage_oprncv);
imwrite("1.jpg",dstImage_oprncv);
//自定义卷积
Mat dstImage_mycov(srcImage.rows,srcImage.cols,CV_8UC1,Scalar(0));
Convlution(srcImage,dstImage_mycov,Kernel_test_3_3);
imshow("卷积图3",dstImage_mycov);
imwrite("2.jpg",dstImage_mycov);
waitKey(0);
return 0;
}
在不使用防溢出的情况下效果如下:
原图:
对原图的灰度图使用filter2D:
对原图的灰度图使用Convlution:
然后我们加入防溢出,再看下效果:
对原图的灰度图使用Convlution:
发现和filter2D函数的效果已经没什么区别了,由于函数设计没有考虑边界填充的情况,所以四周是由黑边的,但是这不是本篇内容的重点,暂时忽略它吧,那么为什么加入了防溢出效果就差了这么多么,大家注意到,在上面的程序中,我们注释了几行代码,如果把它解开的话,就可以看到打印的效果了:
没有防溢出-30 防溢出0 没有防溢出写入了什么?226
没有防溢出257 防溢出255 没有防溢出写入了什么?1
我们拿出两条打印结果来看一下,当计算的像素值超过了255,那么防溢出之后会变成255,如果计算的像素值超过了小于0,那么防溢出之后会变成0,而如果没有加防溢出,直接向图片里面写入的话会写进入什么值呢?
-30变成了226 257变成1
可以看到,OpenCV为了让图片可以正常的显示,会把一个负值加上256,把一个超过256的正值减下去256,这样就会出现上面那种奇怪的结果了。