本文目录
1. 像素读写
2. 图像通道与均值方差计算
3. 算术操作与调整图像的亮度和对比度
4. 基于权重的图像叠加
5. Mat的其他各种像素操作
1. 像素读写
- Mat作为
图像容器,其数据部分存储了图像的像素数据,我们可以通过相关的API来获取图像数据部分; - 在获取图像数据的时候,知道
Mat的类型与通道数目关重要,
根据Mat的类型与通道数目,开辟适当大小的内存空间,
然后通过get方法就可以循环实现每个像素点值的读取、修改,
然后再通过put方法修改与Mat对应的数据部分。
常见的Mat的像素读写get与put方法支持如下表:
- 默认情况下,
imread方式将Mat对象类型加载为CV_8UC3,
本系列笔记跟随原著默认提到的加载图像文件均为Mat对象、类型均为CV_8UC3、通道顺序均为BGR。 - 上表中所列举的是当前OpenCV支持的读取图像的方法;
使用时若需要将像素值写入到Mat对象中,使用与每个get方法相对应的put方法即可。 - 根据
开辟的缓存区域data数组的大小,
读写像素既可以每次从Mat中读取一个像素点数据,
或者可以每次从Mat中读取一行像素数据,
还可以一次从Mat中读取全部像素数据。
下面演示对Mat对象中的每个像素点的值都进行取反操作,并且分别用这三种方法实现像素操作。
- 首先要将图像
加载为Mat对象,
然后获取图像的宽、高以及通道数channels(特别注意这三个值,接下来一直用到,尤其channels):
Mat src = Imgcodecs.imread(fileUri.getPath());
if(src.empty()){
return;
}
int channels = src.channels();
int width = src.cols();
int height = src.rows();
接下来便可以通过方才所述三种方式读取像素数据、修改、写入并比较它们的执行时间。
1.1.从Mat中每次读取一个像素点数据
对于CV_8UC3的Mat类型来说,对应的数据类型是byte;
则先初始化byte数组data,用来存取每次读取出来的一个像素点的所有通道值,数组的长度取决于图像通道数目。
完整代码如下:
byte[] data = new byte[channels];
int b=0, g=0, r=0;
for(int row=0; row<height; row++) {
for(int col=0; col<width; col++) {
// 读取
src.get(row, col, data);//!!!!!!!!!!!!!!!!!!!!!!!读取一个px
b = data[0]&0xff;
g = data[1]&0xff;
r = data[2]&0xff;
// 修改
b = 255 - b;
g = 255 - g;
r = 255 - r;
// 写入
data[0] = (byte)b;
data[1] = (byte)g;
data[2] = (byte)r;
src.put(row, col, data);
}
}
补充诠释:
- 一个px有多个通道;
- 一个通道配给它一个数组元素;
- 1.2中逐行读取时的一个列(某行中的某个列其实就是一个数组元素而已)不是px,
而只是某个px的一个channel而已;- 1.3 同理
- 即1.2 以及1.3 中,data的一个元素,不是px,而只是某个px的一个channel而已;
1.2 从Mat中每次读取一行像素数据
首先需要定义每一行像素数据数组的长度,这里为图像宽度乘以每个像素的通道数目。
接着循环修改每一行的数据;
这里get方法的第二个参数 col = 0的意思是从每一行的第一列开始获取像素数据。
完整代码如下:
// each row data
byte[] data = new byte[channels*width];//channels 是一个px的通道数;width是一个行的px的个数;
// loop
int b=0, g=0, r=0;
int pv = 0;
for(int row=0; row<height; row++) {
src.get(row, 0, data);
/*get一整行的px数据,存进data;形象地说,是以 位置是(row, 0)的第一个px的第一个channel为起始元素,获取一个data长度的数据;
数据一个元素(channel)一个元素(channel)地存进数组data, 每个元素是某个px的一个channel;*/
for(int col=0; col<data.length; col++) {//行中循环列,处理内容:修改一整行的数据
// 读取
pv = data[col]&0xff;
// 修改
pv = 255 - pv;
data[col] = (byte)pv;
}
// 至此,data蓄满一行修改好的px(channel)数据
// 写入
src.put(row, 0, data);
}
关于代码的补充诠释:
byte[] data = new byte[channels*width];中:
channels 是一个px的通道数;
width是一个行的px的个数;for(int row=0; row<height; row++):外层 for 循环行;src.get(row, 0, data);get一整行的px数据,存进data;
形象地说,
是以 位置是(row, 0)即第一个px的第一个channel为起始元素,
获取一个data长度的数据;
数据一个元素(channel)一个元素(channel)地存进数组data,
每个元素是某个px的一个channel;for(int col=0; col<data.length; col++)次层 for ,
行中循环列,处理内容:修改一整行的数据;- 次层for执行完毕,data蓄满一行修改好的px(channel)数据;
src.put(row, 0, data):数组对象引用赋给行首,交付整行数据;
形象地说,
是以 位置是(row, 0)的第一个px的第一个channel为起始元素,
提交一个data长度的数据,即一整行;
1.3 从Mat中一次读取全部像素数据
- 首先定义
数组长度,这里为图像宽度×图像高度×通道数目,
然后一次性获取全部像素数据,
即get的前面两个参数row=0、col=0,表示从第一个像素的第一个channel开始读取。
完整代码如下:
// all pixels
int pv = 0;
byte[] data = new byte[channels*width*height];
src.get(0, 0, data);
for(int i=0; i<data.length; i++) {
pv = data[i]&0xff;
pv = 255-pv;
data[i] = (byte)pv;
}
src.put(0, 0, data);
关于代码的补充诠释(参考1.2的补充,不难理解):
src.get(0, 0, data);get全部的px数据,存进data;
形象地说,
是以 位置是(0, 0)即第一个px的第一个channel为起始元素,
获取一个data长度的数据;
数据一个元素(channel)一个元素(channel)地存进数组data,
每个元素是某个px的一个channel;src.put(0, 0, data):数组对象引用赋给行首,交付全部数据;
形象地说,
是以 位置是(0, 0)的第一个px的第一个channel为
OpenCV Android图像处理:像素操作详解

本文详细介绍了在Android中使用OpenCV进行图像处理的像素操作,包括像素读写、图像通道与均值方差计算、算术操作、权重叠加及归一化等。内容涵盖从Mat对象中读取像素点、行数据和全部像素,以及图像通道分离与合并、亮度和对比度调整等实用技巧。
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



