【问题标题】:OpenCV C++ - How can I replace the value of each pixel with the average value of the grayscale in a 3x3 neighborhood?OpenCV C++ - 如何用 3x3 邻域中的灰度平均值替换每个像素的值?
【发布时间】:2020-04-08 18:58:53
【问题描述】:

我是 OpenCV(C++ 语言)和图像处理的新手。我想,给定一个灰度图像来替换每个像素的值,计算 3x3 邻域中灰度的平均值。

首先我打开图片

Mat img = imread(samples::findFile(argv[1]), IMREAD_GRAYSCALE);

// Example of image
[4 3 9 1,
 2 9 8 0,
 3 5 2 1,
 7 5 8 3]

为了获得角的 3x3 最接近像素(左上、右上、左下和右下)的平均值,我对图像进行了填充:1x1x1x1 恒定边框

Mat imgPadding;
copyMakeBorder(img, imgPadding, 1,1,1,1, BORDER_CONSTANT, Scalar(0));

// Padding example
[0 0 0 0 0 0,
 0 4 3 9 1 0,
 0 2 9 8 0 0,
 0 3 5 2 1 0,
 0 7 5 8 3 0,
 0 0 0 0 0 0]

现在我在输出图像方面遇到了一些问题。我尝试了各种方式,但没有办法让我找到解决方案。我试过这个,使用mean() function 来获得Rect() method 得到的第 i,j 个 3x3 矩阵的平均灰度值。 for 循环从第一个非填充像素开始,到最后一个非填充像素结束。

Mat imgAvg = Mat::zeros(img.rows, img.cols, img.type());
// initialization of the output Mat object with same input size and type

for (int i = 1; i < imgAvg.rows; i++)
    for (int j = 1; j < imgAvg.cols; j++) 
        imgAvg.at<Scalar>(Point(j - 1, i - 1)) = mean(imgPadding(Rect(j - 1, i - 1, 3, 3)));

但我得到了这个运行时错误

main: malloc.c:2379: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.

我也尝试随机缩小范围

for (int i = 1; i < imgAvg.rows - 35; i++)
    for (int j = 1; j < imgAvg.cols - 35; j++) 
        imgAvg.at<Scalar>(Point(j - 1, i - 1)) = mean(imgPadding(Rect(j - 1, i - 1, 3, 3)));

我得到了这个奇怪的输出:screenshot

提前致谢!

编辑: 谢谢大家的回答,我还不知道blur() 功能。 这样我就导入了图片,直接调用了模糊函数

Mat img = imread(samples::findFile(argv[1]), IMREAD_GRAYSCALE);
Mat imgAvg = Mat::zeros(img.rows, img.cols, img.type());

blur(img, imgAvg, Size(3, 3));

但由于我还是初学者,我认为分配给我的练习的目的是编写“手工”代码,我也尝试了这个可行的解决方案

for (int i = 1; i <= imgAvg.rows; i++)
    for (int j = 1; j <= imgAvg.cols; j++) 
        imgAvg.at<uint8_t>(Point(j - 1, i - 1)) = mean(imgPadding(Rect(j - 1, i - 1, 3, 3)))[0];

Result of the algorithm (identical for both solutions)

【问题讨论】:

  • 这就是blur 所做的。
  • 您的阅读越界,应该是:i &lt; imgAvg.rows-1j &lt; imgAvg.cols-1。您有深度 == 1 的图像,一种颜色分量为灰度,值存储在 uint8_t 类型中。因为 cv::mean 返回 Scalar,所以您应该在 0 索引处获取它的第一个元素,并将其分配给 uint8_t:imgAvg.at&lt;uint8_t&gt;(..) = mean(...)[0];
  • @rafix07 这是我正在寻找的解决方案。除了越界错误,我不知道要在模板imgAvg.at&lt;&gt;() 中插入哪种类型。

标签: c++ opencv


【解决方案1】:

只需对图像应用平滑过滤器 - imgproc 模块中的 blur 函数应该可以满足您的需要。文档中有一个很好的例子:https://docs.opencv.org/3.4/dc/dd3/tutorial_gausian_median_blur_bilateral_filter.html

在这种情况下,您需要的参数是图像 (img)、目标图像 (dst) 和内核大小 (ksize),在这种情况下为 3:

src = ...
Mat dst = Mat::zeros( src.size(), src.type() )
blur( src, dst, Size( 3, 3 ))

手动平滑不会像以前那样高效,而且更容易出错。

祝你好运!

【讨论】:

  • 它应该作为评论发布。
【解决方案2】:

您想要做的是在图像处理中称为“框过滤”。在 OpenCV 中你可以这样做:

cv::blur(src_img, 
         dest_img, // same shape and type as src, cannot be src
         cv::Size(3, 3))  // use a kernel of size 3x3           

默认填充是反映边框像素,不会扭曲图像统计信息。如果您喜欢不同的边框模式,请参阅documentation

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-09
    • 2016-09-03
    • 2019-05-03
    • 2017-09-01
    • 2016-06-05
    • 2019-10-07
    • 2017-11-01
    • 1970-01-01
    相关资源
    最近更新 更多