C - RGB 值 - 计算模糊滤镜的 RGB 值的平均值

2024-02-17

前两个并不难,但第三个让我生气。 模糊滤波器必须计算某些像素组的 RGB 值的平均值,以便替换中心像素的值。 想象一个 3x3 的网格,其中中心的像素必须使用周围八个像素的平均值和中心像素本身的 RGB 值进行操作。

到目前为止我所做的如下:

// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
    int n;
    int m;
    int averageRed;
    int averageBlue;
    int averageGreen;

    //For each row..
    for (int i = 0; i < height; i++)
    {
        //..and then for each pixel in that row...
        for (int j = 0; j < width; j++)
        {

            //...if i and j equal 0...         
            if (i == 0 && j == 0)
            {
                for (m = i; m <= 1; m++)
                {
                    for (n = j; n <= 1; n++)
                    {
                        averageRed = averageRed + image[m][n].rgbtRed;
                        averageBlue = averageBlue + image[m][n].rgbtBlue;
                        averageGreen = averageGreen + image[m][n].rgbtGreen;

                        printf("%i\n", averageRed);
                        printf("%i\n", averageBlue);
                        printf("%i\n", averageGreen); 
                    }
                }

                image[i][j].rgbtRed = round((float)averageRed / 4);
                image[i][j].rgbtBlue = round((float)averageBlue / 4);
                image[i][j].rgbtGreen = round((float)averageGreen / 4);

                printf("%i\n", image[i][j].rgbtRed);
                printf("%i\n", image[i][j].rgbtBlue);
                printf("%i\n", image[i][j].rgbtGreen);
            }


            //If i equals 0 and j is greater than 0...
            else if (i == 0 && j > 0)
            {
                //..take the line that equals i..
                for (m = i; m <= 1; m++)
                {
                    //..and take from each pixel ot that line...
                    for (n = j - 1; n <= 1; n++)
                    {
                        //..the color values and add them to the average-variables
                        averageRed = averageRed + image[m][n].rgbtRed;
                        averageBlue = averageBlue + image[m][n].rgbtBlue;
                        averageGreen = averageGreen + image[m][n].rgbtGreen;
                    }
                }

                //Set the current pixel values to the averages
                image[i][j].rgbtRed = round((float)averageRed / 6);
                image[i][j].rgbtBlue = round((float)averageBlue / 6);
                image[i][j].rgbtGreen = round((float)averageGreen / 6);

                printf("%i\n", image[i][j].rgbtRed);
                printf("%i\n", image[i][j].rgbtBlue);
                printf("%i\n", image[i][j].rgbtGreen);
            }


            else if (i > 0 && j == 0)
            {
                for (m = i - 1; m <= 1; m++)
                {
                    for (n = j; n <= 1; n++)
                    {
                        averageRed = averageRed + image[m][n].rgbtRed;
                        averageBlue = averageBlue + image[m][n].rgbtBlue;
                        averageGreen = averageGreen + image[m][n].rgbtGreen;
                    }
                }

                image[i][j].rgbtRed = round((float)averageRed / 6);
                image[i][j].rgbtBlue = round((float)averageBlue / 6);
                image[i][j].rgbtGreen = round((float)averageGreen / 6);
            }


            else if (i > 0 && j > 0 )
            {

                // ..take every line from i - 1 to i + 1...
                for (m = i - 1; m <= 1; m++)
                {

                    //...and in each line take every pixel from j - 1 to j + 1...
                    for (n = j - 1; n <= 1; n++)
                    {

                        //...and add the RGB value to average-variables
                        averageRed = averageRed + image[m][n].rgbtRed;
                        averageBlue = averageBlue + image[m][n].rgbtBlue;
                        averageGreen = averageGreen + image[m][n].rgbtGreen;
                    }
                }

                //Set current value to the rounded average
                image[i][j].rgbtRed = ((float)averageRed / 9);
                image[i][j].rgbtBlue = ((float)averageBlue / 9);
                image[i][j].rgbtGreen = ((float)averageGreen / 9);
            }  


        }

    }
    return;

}

编译工作没有任何抱怨,但结果有点奇怪(特别是前四个块) - Test.bmp 只是一个 55px x 55px 黑白 bmp 文件:

> ~/pset4/filter/ $ ./filter -b images/test.bmp blur.bmp0 38118032 0 0
> 38118032 0 0 38118032 0 0 38118032 0 helpers.c:93:40: runtime error:
> 9.52951e+06 is outside the range of representable values of type 'unsigned char' 0 164 0 helpers.c:120:40: runtime error: 6.35303e+06
> is outside the range of representable values of type 'unsigned char' 0
> 137 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0
> 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160
> 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0
> 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0
> 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160
> 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0 160 0 0
> 160 0 0 160 0 helpers.c:142:40: runtime error: 6.35311e+06 is outside
> the range of representable values of type 'unsigned char'
> helpers.c:167:40: runtime error: 4.23546e+06 is outside the range of
> representable values of type 'unsigned char' ~/pset4/filter/ $

预先非常感谢您的任何建议!

Greetz


注意average*变量是未初始化的,所以当你对它们求和时,你就得到了 UB。它们需要预设为 0,当然是在一开始,但可能是在每个主循环之前。


此外,除了其他人注意到的其他问题之外,您可能还需要执行以下操作饱和 math.

那是因为为了rgbt* (e.g. rgbtRed) is a byte,因此该值可能会被错误地裁剪。

你正在做:

image[i][j].rgbtRed = round((float)averageRed / 6);

这可以重写为:

averageRed = round((float)averageRed / 6);
image[i][j].rgbtRed = averageRed;

但是,如果(例如)averageRed是 256,那么rgbtRed最终结果为 1 [因为分配给image是[有效地]:

image[i][j].rgbtRed = averageRed & 0xFF;

因此,您存储的不是鲜红色,而是接近黑色。最终需要为 255,即“饱和”最大颜色值。

因此,要解决这个问题[或只是为了防止它],请执行以下操作:

averageRed = round((float)averageRed / 6);
if (averageRed > 255)
    averageRed = 255;
image[i][j].rgbtRed = averageRed;

Edit:经过进一步思考,只有在右侧的情况下才需要执行此操作can超过 255,但我[现在]不确定是否可以。要检查这一点,您可以添加(例如):

if (averageRed > 255) {
    fprintf(stderr,"value overflow\n");
    exit(1);
}

你可以把它包装在一个#ifdef,进行测试,如果不触发,可以稍后将其删除。


UPDATE:

这个问题听起来可能很愚蠢,但是这个值怎么可能达到 256呢?即使每个像素都是白色,没有一个值可以达到 256 或者我的错误在哪里? (1 白色 Px: 255 255 255 -> 10 白色 Px: 2550 2550 2550 / 10 --> .....

是的,根据我上面的“编辑:”,可能不会。我最近回答了一个类似的问题,其中的价值could超过255。

但是,您的运行时错误表明该值does超过一个字节的容量(即unsigned char).

这可能是由于未初始化的 sum 变量造成的。

但是,也有它is因为总和/平均值变量是not在循环开始时被重置。你never重置它们,让它们继续成长。

在完成每个 3x3 卷积核后(即存储每个输出像素后),需要重置它们。

而且,我不认为你的for (n = j; n <= 1; n++)循环是正确的。您正在混淆绝对坐标值(来自j)和坐标偏移。

你可能想要这样的东西:

for (m = -1; m <= 1; m++) {
    for (n = -1; n <= 1; n++) {
        averageRed += image[i + m][j + n].rgbtRed;
    }
}

更新#2:

使用一些额外的限制变量来拥有一组循环可能会更容易。

此外,在每个像素的基础上,使用浮点(即round) 可slow。虽然我没有这样做,但它可以很容易地用整数数学代替。

此外,使用更具描述性的名称而不是i, j, m, n可以帮助使代码更容易理解和维护。

不管怎样,这是你的函数的一个稍微重构的版本,它更简单一些:

#include <math.h>

#if 1
typedef struct {
    unsigned char rgbtRed;
    unsigned char rgbtGreen;
    unsigned char rgbtBlue;
} __attribute__((__packed__)) RGBTRIPLE;
#endif

// Blur image
void
blur(int height, int width,
    RGBTRIPLE image[height][width],
    RGBTRIPLE imgout[height][width])
{
    int wid = width - 1;
    int hgt = height - 1;
    RGBTRIPLE *pixel;

    // For each row..
    for (int ycur = 0;  ycur <= hgt;  ++ycur) {
        int ylo = (ycur == 0) ? 0 : -1;
        int yhi = (ycur == hgt) ? 0 : 1;

        // ..and then for each pixel in that row...
        for (int xcur = 0;  xcur <= wid;  ++xcur) {
            int xlo = (xcur == 0) ? 0 : -1;
            int xhi = (xcur == wid) ? 0 : 1;

            int avgRed = 0;
            int avgGreen = 0;
            int avgBlue = 0;

            for (int yoff = ylo;  yoff <= yhi;  ++yoff) {
                for (int xoff = xlo;  xoff <= xhi;  ++xoff) {
                    pixel = &image[ycur + yoff][xcur + xoff];
                    avgRed += pixel->rgbtRed;
                    avgGreen += pixel->rgbtGreen;
                    avgBlue += pixel->rgbtBlue;
                }
            }

            int tot = ((yhi - ylo) + 1) * ((xhi - xlo) + 1);

            pixel = &imgout[ycur][xcur];
            pixel->rgbtRed = roundf((float) avgRed / tot);
            pixel->rgbtGreen = roundf((float) avgGreen / tot);
            pixel->rgbtBlue = roundf((float) avgBlue / tot);
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C - RGB 值 - 计算模糊滤镜的 RGB 值的平均值 的相关文章

随机推荐

  • 如何将SIRI集成到iPhone应用程序中? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我正在开发一个 iPad 应用程序
  • 如何在 jQuery Ajax 成功回调中处理我的 JSON 数据?

    如果我有一个ajax调用 ajax url url dataType json data data success function json data What s the efficient way to extract the JSO
  • Babel:ES6 中的函数参数类型

    如果我编写以下代码并将其转译为通天塔 6 5 0 它工作正常 function foo first string second number code here string and number刚刚从转译的 ES5 代码中删除 如果我使用
  • C#、F#、IronPython 和 IronRuby 的集成

    有人告诉我 由 C 和 F 源代码生成的程序集文件是可以互操作的 因为它们被编译成 NET 程序集 Q1 这是否意味着 C 可以像调用 C 函数一样调用 F 函数 Q2 IronPython 和 IronRuby 怎么样 我没有看到来自 I
  • 一个或多个数组的加权洗牌?

    使用嵌套数组中的权重对一个或多个数组进行混洗的好算法是什么 Example array array array name gt John rank gt 3 array name gt Bob rank gt 1 array name gt
  • 判断 __getattr__ 是方法还是属性调用

    有什么方法可以使用 getattr 确定方法和属性调用之间的区别吗 I e in class Bar object def getattr self name if THIS IS A METHOD CALL Handle method c
  • 如何在 Google AppEngine 平台上访问 Fauxton?

    我正在 Google App Engine 上创建一个离线优先的应用程序 其中 PouchDB 作为我的本地数据库 CouchDB 作为我的远程数据库 我已在 Google AppEngine 上启用了 CouchDB 并尝试访问以下 UR
  • 今天小部件在应用程序更新后没有响应

    我今天的小部件有一个奇怪的案例 我的应用程序有一个小部件来向用户显示一些信息 小部件上有一些按钮 用户可以点击按钮来获取不同的信息 奇怪的是 我正在开发我的应用程序的新版本 我需要测试一下 当我在旧版本上安装新的临时版本应用程序时 我的小部
  • Python f.write() 不接受更多参数

    我有这样的Python代码 f open nv csv a a 10 3 b 3 12 c 3 13 f write a b c 这将输出返回为 f write a b c TypeError function takes exactly
  • 如何在 PHP 中将字符串转换为数字?

    我想转换这些类型的值 3 2 34 0 234343 等到一个数字 在 JavaScript 中我们可以使用Number 但是PHP中有类似的方法吗 Input Output 2 2 2 34 2 34 0 3454545 0 345454
  • 如何使用React Router将数据从一个页面传递到另一个页面

    请我需要有关react router dom的帮助 我是这个库的新手 似乎可以找到任何解决方案 我从 api 调用中得到三个结果 其中我映射数据以将其呈现在 UI 上 现在我需要的是 如果我单击此列表之一上的一行 我希望它带我到屏幕仅显示我
  • Calendar.WEEK_OF_MONTH 在两个不同的设备上给出不同的结果

    我有两台设备 HTC Android 2 3 5 和 Samsung Android 2 3 6 现在我面临的问题是 我需要日期是一个月中的第几周 所以我编写了这段代码并安装在两部手机上 并将系统日期设置为 2013年1月27日 Calen
  • 无法使用runtime.exec重新启动设备

    由于某种原因 我无法使用 Runtime getRuntime exec system bin reboot 重新启动 Android 设备 我已经在 3 台设备上尝试了以下代码 但没有成功 一个是从 rowboat android 源代码
  • 如何使用触控板在 Java AWT ScrollPane 中进行水平鼠标滚轮滚动

    与许多现代鼠标和触控板一样 我的笔记本电脑支持垂直和水平滚动 一旦你习惯了 它就会让人上瘾 我只是希望我的 Java 应用程序支持通过触控板 鼠标滚轮进行水平滚动 但在我搜索的所有地方似乎这在 Java 中是不可能的 我真的希望有人告诉我我
  • 使用内存中查询实现自定义 QueryProvider

    我正在尝试创建一个包装器可查询库 https github com re motion Relinq blob develop Core QueryableBase cs and INh查询提供者 https github com nhib
  • iOS 下载和解析大型 JSON 响应导致 CFData(存储)泄漏

    用户第一次打开我的应用程序时 我需要下载大量数据 我从服务器以 JSON 形式获取所有这些数据 根据用户的不同 这些 JSON 文件的大小可以从 10kb 到 30mb 不等 而且数量超过 10 个 当 JSON 的记录不超过 500 条左
  • 立场:React Native中的绝对问题

    我正在制作一个反应本机应用程序 其中有一个左侧和右侧部分 左侧部分包括flex 0 7右侧部分包括flex 0 2 在左侧部分内 我有一个容器 里面有一个ImageBackground https reactnative dev docs
  • MongoDB 查询 - 限制名称与模式匹配的字段

    我已经阅读了有关 MongoDB 中投影的所有内容 我希望这很简单 但由于 Mongo 查询的巨大灵活性 我错过了它 在我们的 MySql 数据库中 我们采用了一种业务实践 即为 隐藏 字段添加下划线前缀 我们的应用程序知道如何隐藏这些字段
  • PHP 中同时调用多个 API

    我正在处理一个场景搜索页面 http www idynbiz com web html carcrawler 该搜索页面必须同时对以下 5 个搜索引擎进行 API 调用 http www kijiji ca http www kijiji
  • C - RGB 值 - 计算模糊滤镜的 RGB 值的平均值

    前两个并不难 但第三个让我生气 模糊滤波器必须计算某些像素组的 RGB 值的平均值 以便替换中心像素的值 想象一个 3x3 的网格 其中中心的像素必须使用周围八个像素的平均值和中心像素本身的 RGB 值进行操作 到目前为止我所做的如下 Bl