图像与数据类型的对应,以及如何显示

1、normalize函数

void cv::normalize(InputArry src,InputOutputArray dst,double alpha=1,double beta=0,int norm_type=NORM_L2,int dtype=-1,InputArray mark=noArry())

(1)函数的作用

将输入图像src归一化。

注意:alpha、beta作为规范范围的上下限,代表的是输入图像数据类型的显示范围。

ex:对于32F位图像,因为显示范围是0—1,所以alpha、beta为0、1,才能显示与保存。

normalize(img,img, 0, 1, NORM_MINMAX);

imshow(img);

对于16U位图像,因为显示范围是0—65535,所以alpha、beta为0、65535,才能显示与保存。

normalize(img,img, 0, 65535, NORM_MINMAX);

normalize(img,img,-32768, 32767, NORM_MINMAX);//CV_16S的归一化

imshow(img);

(2)参数说明 

src               输入数组;
dst               输出数组,数组的大小和原数组一致;
alpha           1,用来规范值,2.规范范围,并且是下限;
beta             只用来规范范围并且是上限;
norm_type   归一化选择的数学公式类型;
dtype           当为负,输出在大小深度通道数都等于输入,当为正,输出只在深度与输如不同,不同的地方游dtype决定;
mark            掩码。选择感兴趣区域,选定后只能对该区域进行操作。

2、mat.type()函数

opencv中Mat存在各种类型,其中mat有一个type()的函数可以返回该Mat的类型。类型表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量。具体的有以下值:

通道数我们可以发现,C4=C3+8、C3=C2+8、C2=C1+8
在这里插入图片描述

Unsigned 8bits uchar 0~255
Mat: CV_8UC1, CV_8UC2, CV_8UC3, CV_8UC4

Signed 8bits char -128~127
Mat: CV_8SC1,CV_8SC2,CV_8SC3,CV_8SC4

Unsigned 16bits ushort 0~65535
Mat: CV_16UC1,CV_16UC2,CV_16UC3,CV_16UC4

Signed 16bits short -32768~32767
Mat: CV_16SC1,CV_16SC2,CV_16SC3,CV_16SC4

Signed 32bits int -2147483648~2147483647
Mat: CV_32SC1,CV_32SC2,CV_32SC3,CV_32SC4

Float 32bits float -1.18*10-38~3.40*10-38 
Mat: CV_32FC1,CV_32FC2,CV_32FC3,CV_32FC4

Double 64bits double 
Mat: CV_64FC1,CV_64FC2,CV_64FC3,CV_64FC4

一、显示数据类型

#include <iostream>
#include <sstream>
#include <time.h>
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>

#include <pcl/visualization/cloud_viewer.h>
#include <pcl/io/io.h>  
#include <pcl/io/pcd_io.h>  

using namespace cv;
using namespace std;
using namespace pcl;

int main()
{
	Mat img = imread("12.bmp");
	cout << img.type() << endl;
	imshow("11", img);
	waitKey(0);
	system("pause");
	return 0;
}

 因为type()=16=0:所以是CV_8U类型,可以使用imshow直接显示。

 二、imshow和imwrite函数

imshow
opencv的imshow函数都只能对像素值处于0-255范围内的图像进行显示。也就是说,无法使用OpenCV提供的接口函数显示诸如CV_16S等非8位数据格式的视差图/深度图,只能转换成CV_8U格式进行操作。
其实,人眼对灰度级的敏感度比较低、根本无法分辨256级灰度值。而对视差图/深度图进行显示,也只是为了比较直观的验证视差图/深度图的准确性(如颜色随距离逐层变化),所以说完全没必要对216 =65536级灰度进行显示,转换成CV_8U格式就能完全满足需求,这也许就是为什么OpenCV没有提供这样接口的原因之一吧。

imwrite
而存储的话,imwrite函数在关于保存为不同深度格式时候的图像类型支持说明如下:

8位的图像(CV_8U),支持png/jpg/bmp/webp等各种常见图像格式
16位的图像(CV_16U),支持png/jpeg2000/TIFF格式
32位的图像(CV_32F),支持PFM/TIFF/OpenEXR/TIFF/HDR
在要保存为指定格式之前,可以通过convertTo或者cvtCOLOR进行图像类型或者通道转换之后,再调用imwrite进行保存。

OpenCV默认的图像格式为CV_8UC3,此时图像为3通道、8位RGB图像,每个通道所能表达的灰度阶为2^8=256。而视差图常为CV_16S或CV_32S等,如果直接使用cv::imwrite()保存视差图或深度图,则图像将被转成CV_8U格式,而像素值大于255将会被转成255。

OpenCV提供的接口函数:cv::imwrite()、cv::imshow()都只能对像素值处于0-255范围内的图像进行存储和显示,其他范围内的图像,则会被转成0-255范围进行存储、显示。也就是说,无法使用OpenCV提供的接口函数存储和显示诸如CV_16S格式的视差图/深度图,只能转换成CV_8U格式进行操作。

三、转换为CV_16U/CV_16S,以及如何显示16位图像

(1)转换

转换后的类型=18=2:所以是CV_16U;因为imshow只能显示CV_8U,所以显示为全黑。

#include <iostream>
#include <sstream>
#include <time.h>
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>

#include <pcl/visualization/cloud_viewer.h>
#include <pcl/io/io.h>  
#include <pcl/io/pcd_io.h>  

using namespace cv;
using namespace std;
using namespace pcl;

int main()
{
	Mat img = imread("12.bmp");
	cout << "before="<<img.type() << endl;
	img.convertTo(img, CV_16U);
	cout << "after=" << img.type() << endl;
	imshow("11", img);
	waitKey(0);
	system("pause");
	return 0;
}

(2)显示

方法一:直接将16位转成8位,也就是低于255的不变,高于的全部转位255,数据的实际信息会丢失.如果设置为很大的值,数据丢失的会更大

方法二:进行归一化,数据类型依旧是CV_16U;

#include <iostream>
#include <sstream>
#include <time.h>
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>

#include <pcl/visualization/cloud_viewer.h>
#include <pcl/io/io.h>  
#include <pcl/io/pcd_io.h>  

using namespace cv;
using namespace std;
using namespace pcl;

int main()
{
	Mat img = imread("12.bmp");
	cout << "before="<<img.type() << endl;
	img.convertTo(img, CV_16U);
	cout << "after=" << img.type() << endl;
	方法一
	//img.convertTo(img, CV_8U);
	//cout << "after=" << img.type() << endl;
	
	//方法二
	//进行了0~255的归一化以后,可以显示
	normalize(img,img, 0, 256 * 256, NORM_MINMAX);
	//normalize(img,img,-32768, 32767, NORM_MINMAX);//CV_16S的归一化
	cout << "after=" << img.type() << endl;
	imshow("11", img);
	waitKey(0);
	system("pause");
	return 0;
}

(3)保存 

方法一://16位数据后,直接保存,不会引起数据的丢失,但是保存的是原始的数据

imwrite( "1.png", dst);

方法二:归一化以后再保存
normalize(dst, dst, 0, 256* 256, NORM_MINMAX);

imwrite( "1.png", dst);//进行了0~255的归一化以后,可以显示

四、转换为CV_32F,以及如何显示32位图像 

(1)转换

转换后的类型=21=5:所以是CV_32F;因为imshow只能显示CV_8U,所以显示为全白。

#include <iostream>
#include <sstream>
#include <time.h>
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>

#include <pcl/visualization/cloud_viewer.h>
#include <pcl/io/io.h>  
#include <pcl/io/pcd_io.h>  

using namespace cv;
using namespace std;
using namespace pcl;

int main()
{
	Mat img = imread("12.bmp");
	cout << "before="<<img.type() << endl;
	img.convertTo(img, CV_32F);
	cout << "after=" << img.type() << endl;
	imshow("11", img);
	waitKey(0);
	system("pause");
	return 0;
}

 (2)显示

方法一:直接将32位转成8位,也就是低于255的不变,高于的全部转为255,数据的实际信息会丢失.如果设置为很大的值,数据丢失的会更大

方法二:进行归一化,数据类型依旧是CV_16U;

#include <iostream>
#include <sstream>
#include <time.h>
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>

#include <pcl/visualization/cloud_viewer.h>
#include <pcl/io/io.h>  
#include <pcl/io/pcd_io.h>  

using namespace cv;
using namespace std;
using namespace pcl;

int main()
{
	Mat img = imread("12.bmp");
	cout << "before="<<img.type() << endl;
	img.convertTo(img, CV_32F);
	cout << "after=" << img.type() << endl;
	//方法一
	/*img.convertTo(img, CV_8U);
	cout << "after=" << img.type() << endl;*/
	
	//方法二
	//进行了0~1的归一化以后,可以显示
	normalize(img,img, 0, 1, NORM_MINMAX);
	cout << "after=" << img.type() << endl;
	imshow("11", img);
	waitKey(0);
	system("pause");
	return 0;
}

(3)保存 

归一化以后再保存
normalize(dst, dst, 0, 1, NORM_MINMAX);

imwrite( "1.png", dst);//进行了0~1的归一化以后,可以显示

版权声明:本文为CSDN博主「小鹿焕焕」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_44771627/article/details/123101044

小鹿焕焕

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

OpenCV——对象提取

对象提取,简而言之就是获取指定图像,去除其他图像. 解决思路 二值处理 形态学处理(开运算闭运算,轮廓发现) 横纵比过滤计算 . 代码实现 #include<openc

win opencv编译

参考资料: https://www.cnblogs.com/touch-skyer/p/14343791.html 环境准备: 系统:win10 工具 cmake、vs2019、git 软件包 核心 opencv 选择githu