图像的通道和深度以及图像的像素点操作完全解析

前沿

看了图像处理有一段时间了,但是图像的通道和深度一直不理解,毕竟是比较抽象的概念。现在好好总结下,希望能帮助理解图像的通道和图像的深度。
基于OpenCV3.1.0版本
感谢贾志刚老师的视频以及QQ群
看了 xiaowei_cqu 的博客
看了毛星云的OpenCV3编程入门

图像的深度和通道

图像的深度:
图像中像素点占得bit位数,就是图像的深度,比如:
二值图像:图像的像素点不是0 就是1 (图像不是黑色就是白色),图像像素点占的位数就是 1 位,图像的深度就是1,也称作位图。
灰度图像:图像的像素点位于0-255之间,(0:全黑,255代表:全白,在0-255之间插入了255个等级的灰度)。2^8=255,图像的深度是8。
依次轮推,我们把计算机中存储单个像素点所用的 bit 位称为图像的深度。
图像的通道
有了图像深度的概念,我们知道如果是24位的图像,则这个像素点的颜色的取值范围是:从0到2^24。这个范围特别大,如果我们知道了某店的像素值怎么判断像素点的颜色呢?
我们知道 RGB是基本的三原色,如果我们用8位代表一种颜色,每种颜色最大是255,这样每个像素点的颜色值的范围就是(0-255,0-255,0-255)。这样图像的通道就是3。
灰度图的图像存储模型


灰度图像像素点的存储就是对应的原图从左到右,从上到下,依次排列,每个点的值就是就是像素点的值,每个点的地址就是像素像素点的地址。

RGB图的图像存储模型

RGB彩色图像和灰度图相比,每个像素点都有3个通道。每个通道占的内存空间都是8位。在内存中,RGB 图像的存储是以二维数组的形式。
学习图像的存储就是为了理解图像中像素点的存储情况,有助于我们对每个像素点的操作。

图像中像素点的遍历

注意:我们对图像像素的遍历其实对每个像素点中通道的遍历。以后我们对像素以及通道有关的操作时候,能够更好的理解像素以及通道的概念。
我们以经典的图像的颜色空间压缩为例来进行图像的遍历
什么是颜色空间的颜色呢?
        我们知道,对于3通道的深度是8的 RGB 图像,一共可以有255^3中颜色,如此庞大的颜色对我们的处理很不方便,我们可以对图像的像素进行量化。减小图像的颜色种类,同样也可以达到同样的效果。比如我们把图像的像素减少8倍,则每个通道只能有256/8=32中颜色,这样的话,原来图像的0-7像素点对应量化后的0,原来的图像的8-15对应量化后的图像的1,......原来图像中的248-255对应量化后的32。这样就能实现对图像的压缩。
那么这种办法在编程怎么实现?
很简答的,直接利用C/C++中 int 变量的 “/” 运算,这样的话,像素(0-7)/ 8 =0。同理依次可以得到压缩后像素值。

(1)利用基本的 行和列概念实现像素遍历
   上面的分析知道了,图像的存储就是以二维数组的形式,那我们很好理解如果取一个二维数组中元素?常规的方法就是先确定行,然后再确定列。这样就能把这个元素取出来。OpenCV中Mat类中定义的指针,可以获取某一行的地址,然后确定列数就可以获取我们所需要的地址。
Mat 类中有:Mat.ptr<uchar>(int i=0) 获取像素矩阵的指针,i 是从第零行开始的。这块有点像二维数据的存储那样,二维数组可以当做是若干个一维指针,如果知道了每个行的第一个元素就能遍历这个行所有数据。
具体的程序代码
void colorReduce(Mat& srcImage,Mat& desImage, int n) //srcImage:输入图像,desImage:输出图像,n:减少的倍数
{
    desImage = srcImage.clone();
	int channels = desImage.channels();
	int rows = desImage.rows;
	int cols = desImage.cols*channels;//真正的列数是像素的列数乘以通道数,具体见RGB图像的存储
	for (int i = 0;i < rows;i++)        //双重循环的外循环,遍历图片的行数
	{
		uchar* pt = desImage.ptr<uchar>(i); //获取第 i 行的像素矩阵指针
		for (int j = 0; j < cols; j++)   //双重循环的内循环,遍历图像的列数(包括每个通道数)
		{
			pt[j]=(pt[j]/n)*n+n/2; //通常我们会在后面加上 n/2

		}
	}

}
修改:
内层循环可以用指针实现移动到下一列:
			*pt++=(*pt/n)*n+n/2; 

(2)利用动态地址遍历像素点

void colorReduce2(Mat &src, Mat &dst,int n = 8)
{
	dst = src.clone();
	int cols = src.cols;
	int rows = src.rows;
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			dst.at<Vec3b>(i, j)[0] = (src.at<Vec3b>(i, j)[0] / n)*n + n / 2;
			dst.at<Vec3b>(i, j)[1] = (src.at<Vec3b>(i, j)[1] / n)*n + n / 2;
			dst.at<Vec3b>(i, j)[2] = (src.at<Vec3b>(i, j)[2] / n)*n + n / 2;
		}

	}

}
Mat类中的成员函数 at(int x, int y) 可以用来储存图像元素,但是在编译期间,知道图像的数据类型,我们一定要确保指定的数据类型和矩阵中数据类型符合,因为at方法不会对任何数据类型进行转换。
对于彩色图像,每个像素由三部分组成,通道(BGR)。因此,对于一个包含彩色图像的 Mat ,会返回一个由8位数字组成的向量。OpenCV将此类型向量定义为: Vec3b。存储彩色图像像素代码可以写成:
  image.at<Vec3b>(i,j)[channel] = value; 
其中:(i,j)代表像素点位置,channel 代表 通道。

(3)迭代器操作像素

void colorReduce3(Mat &src, Mat &dst,int n= 8)
{
	dst = src.clone();
	Mat_<Vec3b>::iterator it = dst.begin<Vec3b>(); //初始位置迭代器
	Mat_<Vec3b>::iterator itend = dst.end<Vec3b>();//终止位置迭代器

	for (;it != itend; it++)
	{
         (*it)[0] = ((*it)[0]/n)*n+n/2;
	     (*it)[1] = ((*it)[1]/n)*n+n/2;
		 (*it)[2] = ((*it)[2]/n)*n+n/2;	
	}

}

其中:迭代器是C++中STL的概念。











  • 23
    点赞
  • 100
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
### 回答1: 要生成高光谱图像的真彩色图像,需要将高光谱数据中的每个波段映射到红、绿、蓝三个通道上。以下是使用C语言读取raw格式高光谱图像并将其转换为真彩色图像的基本步骤: 1. 读取raw格式高光谱图像文件。首先需要知道图像的尺寸和波段数。如果图像是按照顺序存储的,则可以按照以下方式读取图像数据: ``` FILE *fp = fopen("input.raw", "rb"); int width = 512; // 假设图像宽度为512 int height = 512; // 假设图像高度为512 int bands = 224; // 假设图像有224个波段 unsigned char *data = (unsigned char *)malloc(width * height * bands * sizeof(unsigned char)); fread(data, sizeof(unsigned char), width * height * bands, fp); fclose(fp); ``` 2. 将每个波段映射到红、绿、蓝三个通道上。这可以通过使用像素索引来完成。假设我们想要将第100个波段映射到红色通道,第50个波段映射到绿色通道,第20个波段映射到蓝色通道,代码如下: ``` unsigned char *rgbData = (unsigned char *)malloc(width * height * 3 * sizeof(unsigned char)); for (int i = 0; i < width * height; i++) { rgbData[i * 3] = data[i * bands + 99]; // 红色通道 rgbData[i * 3 + 1] = data[i * bands + 49]; // 绿色通道 rgbData[i * 3 + 2] = data[i * bands + 19]; // 蓝色通道 } ``` 3. 将映射后的数据保存为真彩色图像。可以使用简单的PPM格式保存真彩色图像。PPM格式包括一个头部和像素数据。头部包括图像宽度、高度和像素深度等信息。像素数据按行存储,每个像素由三个字节表示。下面是保存PPM格式图像的代码: ``` FILE *fp = fopen("output.ppm", "wb"); fprintf(fp, "P6\n%d %d\n%d\n", width, height, 255); fwrite(rgbData, sizeof(unsigned char), width * height * 3, fp); fclose(fp); ``` 完成上述步骤后,生成的真彩色图像将保存为PPM格式的文件,并且可以使用任何PPM查看器来查看。 ### 回答2: 要使用C语言生成raw格式的高光谱图像的真彩色图像,需要先了解raw格式的文件结构和高光谱图像的数据存储方式。 raw格式是未经过压缩和处理的原始图像数据,其中包含着每个像素的颜色信息。而高光谱图像则包含了更多波段的信息,相比传统的RGB图像,高光谱图像能够提供更多细节和广泛的颜色范围。因此,生成真彩色图像的关键是将高光谱图像的多个波段数据映射到RGB颜色空间。 生成真彩色图像的步骤如下: 1. 读取raw格式的高光谱图像文件。可以使用C语言中的文件操作函数(如fopen和fread)来读取文件内容。 2. 解析raw文件的头部信息,获取图像的宽度、高度、波段数等参数。 3. 使用C语言中的动态内存分配函数(如malloc)创建一个三维数组(宽度×高度×3),用于存储真彩色图像的RGB数据。 4. 针对每个像素,根据其波段数据计算出对应的RGB。可以使用线性或非线性的映射方法将高光谱数据映射到RGB颜色空间。根据实际需求可以选择不同的映射函数。 5. 将计算得到的RGB保存到三维数组中。 6. 使用C语言中的图像处理库(如OpenCV)将三维数组保存为真彩色图像文件。也可以使用C语言中的文件操作函数将RGB数据保存到一个新的raw文件中。 7. 释放动态分配的内存空间。 8. 完成图像生成。 以上是一个基本的思路,具体的实现过程需要根据具体的raw格式和高光谱图像的数据存储方式进行调整和优化。可以参考相关的图像处理和文件操作的C语言库函数来简化开发过程。 ### 回答3: 要使用C语言来生成raw格式的高光谱图像的真彩色图像,可以按照以下步骤进行: 1. 首先,需要读取raw格式的高光谱数据。可以使用C语言中的文件处理方法,比如使用fopen函数打开文件,再使用fread函数读取图像数据到内存中。 2. 读取高光谱数据后,需要进行处理来生成真彩色图像。高光谱图像包含多个波段的信息,而真彩色图像通常由红、绿、蓝三个波段的信息组合而成。 3. 为了生成真彩色图像,可以选择高光谱图像中的三个波段作为红、绿、蓝通道的数据。可以根据实际需求,选择高光谱图像中的特定波段,或者对所有波段进行加权平均来分配给红、绿、蓝通道。 4. 按照选择的波段数据,可以通过线性映射将波段数据的范围映射到0-255的像素范围。可以使用公式:newValue = (oldValue - min) * (255 / (max - min)),其中newValue为映射后的像素,oldValue为原始波段数据,min和max为波段数据的最小和最大。 5. 将三个颜色通道的数据重新组合,形成真彩色图像的像素数据。可以使用RGB格式来表示像素,即一个像素点由红、绿、蓝三个分量组成。 6. 最后,将生成的真彩色图像数据保存到一个新的raw格式文件中。使用fwrite函数将像素数据写入文件,再使用fclose函数关闭文件。 通过以上步骤,可以使用C语言生成raw格式高光谱图像的真彩色图像。具体的实现方式可能需要依据具体的需求和数据格式进行适当的调整和处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值