聊一聊OpenCV的saturate_cast防溢出

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,这样就会出现上面那种奇怪的结果了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏hanlp学习笔记

Spark应用HanLP对中文语料进行文本挖掘--聚类

用到的知识:HanLP、Spark TF-IDF、Spark kmeans、Spark mapPartition;

390
来自专栏大数据挖掘DT机器学习

利用word2vec对关键词进行聚类

按照一般的思路,可以用新闻ID向量来表示某个关键词,这就像广告推荐系统里面用用户访问类别向量来表示用户一样,然后就可以用kmeans的方法进行聚类了。不过对于新...

38510
来自专栏人工智能LeadAI

tensorflow的数据输入

tensorflow有两种数据输入方法,比较简单的一种是使用feed_dict,这种方法在画graph的时候使用placeholder来站位,在真正run的时候...

1155
来自专栏程序员互动联盟

【专业领域】QtWebkit里RenderLayer树的绘制详细流程分析

更新:RenderLayer树的绘制对RenderObject的绘制,同时补足绘制阶段的描述。 QtWebkit里,QWebView,QWebPa...

3545
来自专栏hadoop学习笔记

Spark应用HanLP对中文语料进行文本挖掘--聚类详解教程

用到的知识:HanLP、Spark TF-IDF、Spark kmeans、Spark mapPartition;

1040
来自专栏何俊林

流媒体解码及H.264编码推流

3045
来自专栏WOLFRAM

交互式查询化学键信息

1703
来自专栏流媒体

流媒体解码及H.264编码推流简介

这里我们使用了FFmpge的sdk和Opencv的sdk。为了方便测试,我们直接使用在线的rtsp网络流。rtmp://live.hkstv.hk.lxdns....

1484
来自专栏一棹烟波

CUDA与OpenGL互操作

当处理较大数据量的时候,往往会用GPU进行运算,比如OpenGL或者CUDA。在实际的操作中,往往CUDA实现并行计算会比OpenGL更加方便,而OpenGL在...

23810
来自专栏点滴积累

geotrellis使用(八)矢量数据栅格化

目录 前言 栅格化处理 总结 参考链接 一、前言        首先前几天学习了一下Markdown,今天将博客园的编辑器改为Markdown,从编写博客到界面...

4047

扫码关注云+社区