您的位置:首页 > 运维架构

聊一聊OpenCV的saturate_cast防溢出

2017-10-18 20:30 330 查看
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,这样就会出现上面那种奇怪的结果了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: