当前位置:   article > 正文

使用OpenCV Mat对图片低频信息、高频信息提取及无损还原(高斯模糊、做差、求和)_如何利用深度学习将低频图像转换为高频图像

如何利用深度学习将低频图像转换为高频图像

为了还原一篇论文。里面用到了提取图像的低频信息、高频信息、及还原技术。现在使用opencv进行复现,里面有一些注意事项特此记录
参考链接:
OpenCV中对Mat矩阵加、减、乘、除、转置等操作的总结
OpenCV两个Mat相减的隐藏秘密
opencv学习笔记(四)——模糊(均值,高斯,双边)
OpenCV基本数据类型表示的范围大小

其实提取一张图像的低频、高频信息原理比较简单,但是不注意的时候还原出来的影像总有一些像素值对不上(特别是边缘像素)。

影像的低频和高频信息可用如下数学模型表述:
I=L+H
其中I表示影像,L和H分别表示影像对应的低频和高频信息。

图片低频提取

图片低频提取其实就是对原始影像做一次模糊,这里的模糊可以选择均值模糊、高斯模糊、双边模糊,输出的图片即图片的低频信息。
我这里使用参考链接第三个(opencv学习笔记(四)——模糊(均值,高斯,双边)
),进行高斯模糊,提取图片低频信息。

cv::blur(img, img2, Size(11, 11));  //用opencv自带的API进行均值滤波操作

cv::GaussianBlur(RefMat, RefMat_L, cv::Size(GaussR, GaussR), 3, 3);//高斯滤波
  • 1
  • 2
  • 3

图片高频提取及原始影像还原

根据公式H=I - L
把原始影像减去低频信息即可得到高频影像信息。Opencv Mat支持直接相减操作,如参考链接1和参考链接2都说明了可以直接使用两个Mat进行相减操作,代码如下:

cv::Mat SrcDownMat = cv::Mat(Srcdown_H, Srcdown_W, CV_8UC3, ImgThumbBufferMat);//使用buffer数据进行转换成Mat格式,也可以直接使用imread()函数读出Mat

cv::Mat SrcDownMat_L;
cv::GaussianBlur(SrcDownMat, SrcDownMat_L, cv::Size(5, 5), 3, 3);//低频提取
cv::Mat SrcDownMat_H = SrcDownMat - SrcDownMat_L;//高频提取
cv::Mat SrcDownMat_New = SrcDownMat_L + SrcDownMat_H;//还原影像

//存储影像
cv::imwrite("_Srcdown.tiff", SrcDownMat);
cv::imwrite("_Srcdown_L.tiff", SrcDownMat_L);
cv::imwrite("_Srcdown_H.tiff", SrcDownMat_H);
cv::imwrite("_Srcdown_New.tiff", SrcDownMat_New);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

存出来的影像加载arcmap中发现边缘的像素值与原始影像数据值对不上,经过分析问题如下:
1、提取高频的时候,两个影像做差。其格式是CV_8UC3格式(8位,无符号整型,3通道影像)。在做差的时候如果原始影像像素是0,低频信息如果是23,则做差后的结果是0(0-23=0,原因就是其Mat格式是无符号整型),而我们想在后面利用相加还原影像信息,则想要高频信息为-23(0 - 23= -23 ,需要Mat格式是带符号整型的),所以必须在做差前将两个相减的Mat格式转换成带符号的,结果可以保留负数的,从第一篇博客中看到了如下这张图:
在这里插入图片描述
修改上面代码再次实验即可完全还原像素值,最后的代码如下:

cv::Mat SrcDownMat = cv::Mat(Srcdown_H, Srcdown_W, CV_8UC3, ImgThumbBufferMat);//使用buffer数据进行转换成Mat格式,也可以直接使用imread()函数读出Mat

cv::Mat SrcDownMat_L;
cv::GaussianBlur(SrcDownMat, SrcDownMat_L, cv::Size(5, 5), 3, 3);//低频提取

//对Mat格式转换,是为了做差能得到负数,可以更好的还原
SrcDownMat.convertTo(SrcDownMat, CV_32F);
SrcDownMat_L.convertTo(SrcDownMat_L, CV_32F);

cv::Mat SrcDownMat_H = SrcDownMat - SrcDownMat_L;//高频提取
cv::Mat SrcDownMat_New = SrcDownMat_L + SrcDownMat_H;//还原影像

//存储前必须对Mat格式再次转换成CV_8UC3,否则颜色看着很怪异
SrcDownMat_New.convertTo(SrcDownMat_New, CV_8UC3);
SrcDownMat_L.convertTo(SrcDownMat_L, CV_8UC3);
SrcDownMat_H.convertTo(SrcDownMat_H, CV_8UC3);
SrcDownMat.convertTo(SrcDownMat, CV_8UC3);
	
//存储影像
cv::imwrite("_Srcdown.tiff", SrcDownMat);
cv::imwrite("_Srcdown_L.tiff", SrcDownMat_L);
cv::imwrite("_Srcdown_H.tiff", SrcDownMat_H);
cv::imwrite("_Srcdown_New.tiff", SrcDownMat_New);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

输出的影像加载arcMap,像素级别完全无损还原

转换的时候还要注意一下问题:
1、为了节约空间,我不使用 CV_32F格式,将CV_8UC3格式直接转换为CV_8SC3格式,S表示带符号,可以记录负数,感觉没有问题。实际操作也没有问题,但是会出现对半截断的情况。CV_8UC3格式表示范围(0-255),CV_8SC3格式表示范围(-128 - 127),详见:OpenCV基本数据类型表示的范围大小

转换的测试代码

//对Mat格式转换,是为了做差能得到负数,可以更好的还原
SrcDownMat.convertTo(SrcDownMat, CV_8SC3);
SrcDownMat_L.convertTo(SrcDownMat_L, CV_8SC3);
  • 1
  • 2
  • 3

实际效果如下图:
在这里插入图片描述
由于ArcMap会自动拉伸,所以看起来比较亮,这个地方实际像素最大就是127

根据上面原理,想解约一点空间,将代码优化成16位带符号的是可以的,因为16位带符号存储8位无符号像素,不会对其进行截断。代码如下:

SrcDownMat.convertTo(SrcDownMat, CV_16SC3);//转换是为了做差能得到负数,可以更好的还原
SrcDownMat_L.convertTo(SrcDownMat_L, CV_16SC3);
  • 1
  • 2

效果如下:
在这里插入图片描述

以上,特此记录。2022.5.19

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/78442
推荐阅读
相关标签
  

闽ICP备14008679号