OpenCV用指针扫描图像

2022-10-25 17:40:47 浏览数 (2)

前言

在大多数图像处理任务中,我们需要扫描图像的所有像素才能执行计算,由于需要访问大量像素,我们必须以高效的方法进行扫描。本节我们将介绍如何使用指针实现高效扫描图像的方法。我们通过完成减少图像中的颜色数量这一任务来说明图像扫描过程。

用指针扫描图像

彩色图像由三通道像素组成,这些通道中的每一个都对应于红色、绿色和蓝色三种基色之一的强度值。由于这些像素值都是 8 位无符号字符,因此颜色总数为 256 x 256 x 256,超过 1600 万种颜色。因此,为了降低分析的复杂性,减少图像中颜色的数量通常是有效的。实现此目标的一种方法是将 RGB 空间细分为大小相等的立方体。例如,如果我们将每个维度中的颜色数量减少为原来的 1/8,那么可以得到共 32 x 32 x 32 种颜色。此时,原始图像中的每种颜色都会在新的颜色空间中分配一个新的颜色值,该值等于原始颜色值所属的立方体中心的值。

因此,基本的色彩量化(色彩量化即为减少图像中颜色数量的过程)算法很简单。如果 N 是缩减因子,则对于图像中的每个像素和该像素的每个通道,将值除以 N (使用整数除法,舍弃余数);然后,将结果乘以 N,此时获得的值与输入像素值之间的差值为 N 的倍数,然后,只需添加 N/2 即可获得 N 的两个相邻倍数间的中心位置。如果对每个 8 位通道值重复此过程,将获得共 256/N x 256/N x 256/N 个可能的颜色值。

1. 减色函数的签名如下,函数需要提供图像和每个通道的缩减因子 div 作为参数:

代码语言:javascript复制
void colorReduce(cv::Mat image, int div=64);
复制代码

此函数使用原地处理,即输入图像的像素值被函数修改。

2. 只需创建一个遍历所有像素值的双循环即可完成处理。第一个循环扫描每一行,获取行图像数据的指针:

代码语言:javascript复制
for (int j=0; j<image.rows; j  ){
    // 获取行的地址
    uchar* data=image.ptr<uchar>(j);
复制代码

3. 第二个循环遍历行指针的每一列,并使用上述方法减少颜色:

代码语言:javascript复制
    for (int i=0; i<nc; i  ){
        // 处理每个像素
        data[i] = data[i]/div*div   div/2
    }
}
复制代码

通过加载图像并调用 colorReduce 函数来测试该函数:

代码语言:javascript复制
// 读取图像
image= cv::imread("1.png");
// 处理图像
colorReduce(image,64);
// 展示图像
cv::namedWindow("Image");
cv::imshow("Image",image);
复制代码

编译并执行程序,可以得到以下结果:

在彩色图像中,图像数据缓冲区的前三个字节分别用于表示左上角像素的三色通道 (BGR 通道);接下来的三个字节是第一行的第二个像素的三色通道值,依此类推。因此,宽度为 W 、高度为 H 的图像需要 WxHx3uchars 的内存块。但是,出于效率原因,一行图像元素可以填充一些额外的像素,这是因为某些多媒体处理器芯片(例如 Intel MMX 架构)在图像行像素数为 48 的倍数时可以更有效地处理图像,这些额外的像素并不会被显示或保存;它们的确切值会

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情

前言

在大多数图像处理任务中,我们需要扫描图像的所有像素才能执行计算,由于需要访问大量像素,我们必须以高效的方法进行扫描。本节我们将介绍如何使用指针实现高效扫描图像的方法。我们通过完成减少图像中的颜色数量这一任务来说明图像扫描过程。

用指针扫描图像

彩色图像由三通道像素组成,这些通道中的每一个都对应于红色、绿色和蓝色三种基色之一的强度值。由于这些像素值都是 8 位无符号字符,因此颜色总数为 256 x 256 x 256,超过 1600 万种颜色。因此,为了降低分析的复杂性,减少图像中颜色的数量通常是有效的。实现此目标的一种方法是将 RGB 空间细分为大小相等的立方体。例如,如果我们将每个维度中的颜色数量减少为原来的 1/8,那么可以得到共 32 x 32 x 32 种颜色。此时,原始图像中的每种颜色都会在新的颜色空间中分配一个新的颜色值,该值等于原始颜色值所属的立方体中心的值。

因此,基本的色彩量化(色彩量化即为减少图像中颜色数量的过程)算法很简单。如果 N 是缩减因子,则对于图像中的每个像素和该像素的每个通道,将值除以 N (使用整数除法,舍弃余数);然后,将结果乘以 N,此时获得的值与输入像素值之间的差值为 N 的倍数,然后,只需添加 N/2 即可获得 N 的两个相邻倍数间的中心位置。如果对每个 8 位通道值重复此过程,将获得共 256/N x 256/N x 256/N 个可能的颜色值。

1. 减色函数的签名如下,函数需要提供图像和每个通道的缩减因子 div 作为参数:

代码语言:javascript复制
void colorReduce(cv::Mat image, int div=64);
复制代码

此函数使用原地处理,即输入图像的像素值被函数修改。

2. 只需创建一个遍历所有像素值的双循环即可完成处理。第一个循环扫描每一行,获取行图像数据的指针:

代码语言:javascript复制
for (int j=0; j<image.rows; j  ){
    // 获取行的地址
    uchar* data=image.ptr<uchar>(j);
复制代码

3. 第二个循环遍历行指针的每一列,并使用上述方法减少颜色:

代码语言:javascript复制
    for (int i=0; i<nc; i  ){
        // 处理每个像素
        data[i] = data[i]/div*div   div/2
    }
}
复制代码

通过加载图像并调用 colorReduce 函数来测试该函数:

代码语言:javascript复制
// 读取图像
image= cv::imread("1.png");
// 处理图像
colorReduce(image,64);
// 展示图像
cv::namedWindow("Image");
cv::imshow("Image",image);
复制代码

编译并执行程序,可以得到以下结果:

在彩色图像中,图像数据缓冲区的前三个字节分别用于表示左上角像素的三色通道 (BGR 通道);接下来的三个字节是第一行的第二个像素的三色通道值,依此类推。因此,宽度为 W 、高度为 H 的图像需要 WxHx3uchars 的内存块。但是,出于效率原因,一行图像元素可以填充一些额外的像素,这是因为某些多媒体处理器芯片(例如 Intel MMX 架构)在图像行像素数为 48 的倍数时可以更有效地处理图像,这些额外的像素并不会被显示或保存;它们的确切值会被忽略。

0 人点赞