C-rgb值-计算模糊滤镜的rgb值的平均值 [英] C - rgb values - Calculating the average of rgb values for a blur filter

查看:65
本文介绍了C-rgb值-计算模糊滤镜的rgb值的平均值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

前两个不是那么困难,但是第三个让我发疯.模糊滤波器必须计算某些像素组的rgb值的平均值,以替换居中像素的值.想象一下一个3x3的网格,其中中心的像素必须使用八个周围像素的平均值和中心像素本身的rgb值进行操纵.

The first two ones were not so difficult but the third one makes me mad. The blur filter has to calculate an average of the rgb values of certain pixel groups in order to replace the values of the centered pixel. Imagine a 3x3 grid where the pixel in the center has to be manipulated with the rgb values of the average of the eight surrounding pixels and the center-pixel itself.

到目前为止,我所做的是:

What I have done so far is the following:

// 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 ist只是一个55px x 55px黑色/白色bmp文件:

The compiling works without any complaint, but the results are slightly strange (especially the first four blocks) - the Test.bmp ist just a 55px x 55px black/white bmp-file:

> ~/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/ $

非常感谢您提供任何建议!

Thanks very much in advance for any advise!

格里兹

推荐答案

请注意, average * 变量是未初始化的,因此,对它们求和时便拥有UB.一定要在一开始就将它们预设为0,但可能需要在每个主循环之前将其预置.

Note that average* variables are uninitialized, so when you sum to them, you have UB. They need to be preset to 0, certainly at the outset, but possibly before each major loop.

此外,除了其他人指出的其他问题之外,您可能还需要进行饱和度数学运算.

Also, aside from your other issues that others have noted, you may need to do saturation math.

这是因为对于 rgbt * (例如 rgbtRed )是 byte ,因此该值可能会被错误地裁剪.

That's because for rgbt* (e.g. rgbtRed) is a byte, so the value can be clipped incorrectly.

您正在做

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

这可以改写为:

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

但是,如果(例如) averageRed 为256,则 rgbtRed 最终将为1 [因为对 image 的分配是[有效的]:

But, if (e.g.) averageRed was 256, then rgbtRed would end up as 1 [because the assignment to image is [effectively]:

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

因此,您存储的不是黑色,而是存储鲜红色.最终将需要为255,即饱和"最大颜色值.

So, instead of storing bright red, you're storing nearly black. The final would need to be 255, the "saturated" maximum color value.

因此,要解决此问题(或只是为了防止它发生),请执行以下操作:

So, to fix that [or merely to guard against it], do:

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

经过进一步思考,仅当右侧可以超过255时,才需要执行此操作,但是[现在]我不确定它是否可以.要对此进行检查,您可以添加(例如):

Upon further reflection, you only need to do this if the right hand side can exceed 255, but I'm [now] not sure that it can. To check against this, you could add (e.g.):

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

您可以将其包装在 #ifdef 中,进行测试,如果未触发,则可以稍后将其删除.

You could wrap this in an #ifdef, do tests, and if it doesn't trigger, you can remove it later.

更新:

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

As stupid as the question might sound, but how can the value ever reach 256? Even if every pixel is white, none of the values can reach 256 or where is my mistake? (1 white Px: 255 255 255 -> 10 white Px: 2550 2550 2550 / 10 --> .....

是的,根据我上面的",可能没有.我最近回答了一个类似的问题,其中值可以超过255.

Yes, per my "" above, it may not. I recently answered a similar question where the value could exceed 255.

但是,您的运行时错误表明值确实超出了一个字节的容量(即 unsigned char ).

But, your runtime error shows that the value does exceed the capacity of a byte (i.e. unsigned char).

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

That is probably due to the uninitialized sum variables.

但是,也是,因为求和/平均变量在循环开始时不会被重置.您从不重置它们,因此它们只会继续增长.

But, also it is because the sum/average variables are not being reset at the start of a loop. You never reset them, so they just continue to grow and grow.

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

They need to be reset after you complete each 3x3 convolution kernel (i.e. after you store each output pixel).

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

And, I don't think your for (n = j; n <= 1; n++) loops are correct. You're mixing up absolute coordinate values (from j) and coordinate offsets.

您可能想要类似的东西:

You probably want something like:

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


更新#2:

使用一些额外的限制变量,使用一组循环可能会更容易.

It may be easier to have a single set of loops, using some extra limit variables.

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

Also, on a per pixel basis, using floating point (i.e. round) can be slow. Although, I didn't do it, it can be replaced with integer math easily enough.

进一步,使用更多的描述性名称代替 i,j,m,n 可以使代码更易于理解和维护.

Further, using more descriptive names instead of i, j, m, n can help make the code a bit easier to understand and maintain.

无论如何,这是您的函数的某种重构版本,它有点简单:

Anyway, here's a somewhat refactored version of your function that is a bit simpler:

#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);
        }
    }
}

这篇关于C-rgb值-计算模糊滤镜的rgb值的平均值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆