OpenCV使用邻居访问扫描图像

87 阅读2分钟

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

前言

在图像处理中,有时需要根据某个像素的相邻像素的值计算该像素位置的值。当这个邻域包括上一行和下一行的像素时,就需要同时扫描图像的多行像素,本节中,我们将介绍如何执行邻居访问扫描图像。

使用邻居访问扫描图像

为了说明这种扫描方式,我们将应用一个基于拉普拉斯算子的处理函数来锐化图像。在图像处理,如果从图像中减去它的拉普拉斯算子,图像边缘会被放大,从而得到更清晰的图像。锐化值计算如下:

sharpened_pixel= 5*current-left-right-up-down;

其中,left 是紧接在当前像素左侧的像素,up 是上一行的邻居像素,依此类推。接下来,我们介绍如何实现锐化函数。

1. 我们将创建一个带有输入和输出图像的锐化函数,并不使用原地处理,即函数需要提供输出图像:

void sharpen(const cv::Mat &image, cv::Mat &result)

2.分配输出结果图像,通过 channels() 函数获取输入图像的通道数:

result.create(image.size(), image.type());
int nchannels= image.channels();
  1. 接下来,我们循环处理图像中的每一行。图像扫描使用三个指针完成,一个指向当前行,一个指向前一行,另一个指向下一行。此外,由于每个像素计算都需要访问其邻居,因此无法计算图像第一行和最后一行的像素以及第一列和最后一列的像素的值:
for (int j=1; j<image.rows-1; j++) {
    const uchar* previous = image.ptr<const uchar>(j-1);
    const uchar* current = image.ptr<const uchar>(j);
    const uchar* next = image.ptr<const uchar>(j+1);
    uchar* output = result.ptr<uchar>(j);
    for (int i=channels; i<(image.cols-1)*nchannels; i++){
        *output++ = cv::saturate_cast<uchar>(
                    5*current[i]-current[i-nchannels]-current[i+nchannels]-previous[i]-next[i]);
    }
}

以上代码可以在灰度和彩色图像上工作。如果我们将此函数应用于测试灰度图像,可以得到以下结果:

image.png

为了访问前一行和下一行的相邻像素,必须定义附加指针,然后在扫描循环内访问这些行中的像素。

在计算输出像素值时,会根据运算结果调用 cv::saturate_cast 模板函数。这是因为应用于像素的数学表达式可能会导致超出允许像素值范围的结果(即低于 0 或高于 255)。解决方案是将像素值重置到 [0, 255] 范围内,将负值更改为 0 并将超过 255 的值更改为 255,这正是 cv::saturate_cast<uchar> 函数的作用。此外,如果输入参数是浮点数,则结果将四舍五入为最接近的整数。我们也可以将此函数与其他类型一起使用,以确保结果保持在此类型定义的范围内。