【问题标题】:Blurring an Image in c pixel by pixel - special cases逐像素模糊 c 中的图像 - 特殊情况
【发布时间】:2020-06-13 19:35:57
【问题描述】:

我正在开发一个程序,它会稍微模糊 c 中的图像。

知道我需要 8 个周围像素和所选像素的平均值和 rgb 值来更改该像素的颜色,我将它们加在一起并取平均值。

我知道我执行此操作的方式并不是最有效的方式,因此如果有任何关于如何简化此操作的建议,请告诉我。

我计划在最后的第三个 for 循环中将 tempimage 复制回 image

结构 RGBTRIPLE 包含一个像素的 rgb 值。

    BYTE  rgbtBlue;
    BYTE  rgbtGreen;
    BYTE  rgbtRed;

我现在的问题是处理特殊情况,例如图像的边缘或侧面的像素。

当所选像素不被9像素包围时,如何获得周围像素的值?

到目前为止,这是我的代码:

void blur(int height, int width, RGBTRIPLE image[height][width])
{
    // copy all values to temporary image
    RGBTRIPLE tempimage[height][width];
    int avgRed = 0;
    int avgGreen = 0;
    int avgBlue = 0;
    //copy pixels to temp image
    for ( int x = 0; x < height; x++)
    {
        for (int y = 0; y < width; y++)
        {
            tempimage[x][y] = image[x][y];
        }
    }
    //get average of surrounding pixels
    for ( int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            //TODO: edge check
            //surrounding pixels
            avgRed = round(((float)(image[i][j].rgbtRed
            + image[i][j - 1].rgbtRed + image[i][j + 1].rgbtRed
            + image[i - 1][j].rgbtRed + image[i - 1][j - 1].rgbtRed
            + image[i - 1][j + 1].rgbtRed + image[i + 1][j].rgbtRed
            + image[i + 1][j - 1].rgbtRed + image[i + 1][j + 1].rgbtRed)) / 9);

            avgGreen = round(((float)(image[i][j].rgbtGreen
            + image[i][j - 1].rgbtGreen + image[i][j + 1].rgbtGreen
            + image[i - 1][j].rgbtGreen + image[i - 1][j - 1].rgbtGreen
            + image[i - 1][j + 1].rgbtGreen + image[i + 1][j].rgbtGreen
            + image[i + 1][j - 1].rgbtGreen + image[i + 1][j + 1].rgbtGreen)) / 9);

            avgBlue = round(((float)(image[i][j].rgbtBlue
            + image[i][j - 1].rgbtBlue + image[i][j + 1].rgbtBlue
            + image[i - 1][j].rgbtBlue + image[i - 1][j - 1].rgbtBlue
            + image[i - 1][j + 1].rgbtBlue + image[i + 1][j].rgbtBlue
            + image[i + 1][j - 1].rgbtBlue + image[i + 1][j + 1].rgbtBlue)) / 9);


            tempimage[i][j].rgbtRed = avgRed;
            tempimage[i][j].rgbtGreen = avgGreen;
            tempimage[i][j].rgbtBlue = avgBlue;

        }
    }

    //TODO: for loop to copy tempimage back to image here
    return;
}

【问题讨论】:

  • Antialiasing algorithm?的可能重复
  • 你需要选择当像素没有被包围时要做什么。您可以采样更少的像素,或者您可以将最近的像素重新采样到丢失的像素
  • 您不需要将像素复制到临时图像。从源代码中读取,然后将它们分配给临时文件。现在,跳过困难的部分,只做除边界之外的所有事情。使用当前像素的偏移量的循环和查找表。一旦你有了它,你就可以对边缘和角落进行特殊处理..

标签: c image


【解决方案1】:

在像您这样的算法中,有多种方法可以处理“边缘”情况。如果它位于相关边缘,则下面的代码使用当前的“行”或“列”(而不是它的上方/下方或左/右):

for ( int i = 0; i < height; i++)
{
    // Edge check (A for 'above' index and B for 'below'):
    int A = i - 1; if (A < 0) A = 0;
    int B = i + 1; if (B > height - 1) B = height - 1;
    for (int j = 0; j < width; j++)
    {
        // Edge check (L = 'left of', R = 'right of'):
        int L = j - 1; if (L < 0) L = 0;
        int R = j + 1; if (R > width - 1) R = width - 1;
        // Then change all your 'i-1'|'i+i'|'j-i'|j+1' indexes to A|B|L|R:
        avgRed = round(((float)(image[i][j].rgbtRed
        + image[i][L].rgbtRed + image[i][R].rgbtRed
        + image[A][j].rgbtRed + image[A][L].rgbtRed
        + image[A][R].rgbtRed + image[B][j].rgbtRed
        + image[B][L].rgbtRed + image[B][R].rgbtRed)) / 9);
        // ... and similarly for green and blue ...

顺便说一下,我注意到您的像素索引为 image[column][row](= column-major 顺序)。按照惯例,CC++ 二维数组以相反的方式定义,如 image[row][column](= row-major 顺序);但是,只要您确定这是您所拥有的,那就没问题!

【讨论】:

  • 你能给我解释一下你的代码吗?与所有A | B | L | R 关联的if 语句不应该重置A | B | L | R 值而不是ij?我看不出 i 或 j 如何超出设定的界限。而且,最后它仍然在计算 9 个像素的平均值 - 我认为这个想法是丢弃超出范围的像素,只计算 6 个像素(边缘情况)或 4 个像素(角落情况)?
  • @DamjanOstrelic 关于你的第一点 - 很好发现(现在编辑更正)!关于第二点,我提供的解决方案是一个确实总是使用 9 像素(但总是 valid 像素)的选项;忽略越界像素并减少除数(到 6 或 4)是另一种(但 * 不同)解决方案。哪个更好取决于环境和用户偏好 - 但“你的”方法需要更多代码。
  • “始终使用 9 个像素”方法的工作原理是假设边缘以外的像素与对应的边缘像素具有相同的颜色;也就是说,它使用边缘作为源颜色,有效地将图像四周扩展了一个像素。
  • 感谢您的澄清,我现在明白了。在边缘使用 9 个像素可能是最简单的方法 - 我会尝试为“丢弃”方法考虑一些东西。 :)
  • @DamjanOstrelic 另请注意,边缘通常是: (b) 通常,图像中的实际“感兴趣区域”不包括边缘。考虑到这些,您必须问:“额外的编码(和执行)时间值得吗?”
【解决方案2】:

当您考虑使用框模糊模糊图像或 n*n matxix 时,此 C 代码运行良好。它考虑顶部、底部和中间行并分别计算像素 RGB。

// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{

    int sumBlue;
    int sumGreen;
    int sumRed;
    //create a temporary table
    RGBTRIPLE temp[height][width];

    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            sumBlue = 0;
            sumGreen = 0;
            sumRed = 0;
            //Top row
            if (i == 0)
            {
                if (j == 0) //top row left corner
                {
                    sumBlue = round(ceil(image[i][j].rgbtBlue
                                         + image[i][j + 1].rgbtBlue
                                         + image[i + 1][j].rgbtBlue
                                         + image[i + 1][j + 1].rgbtBlue) / 4);
                    sumGreen = round(ceil(image[i][j].rgbtGreen
                                          + image[i][j + 1].rgbtGreen
                                          +  image[i + 1][j].rgbtGreen
                                          +  image[i + 1][j + 1].rgbtGreen) / 4);
                    sumRed = round(ceil(image[i][j].rgbtRed
                                        + image[i][j + 1].rgbtRed
                                        + image[i + 1][j].rgbtRed
                                        + image[i + 1][j + 1].rgbtRed) / 4);

                }

                else if (j == width - 1) //top row right corner
                {
                    sumBlue = round(ceil(image[i][j].rgbtBlue
                                         + image[i][j - 1].rgbtBlue
                                         + image[i + 1][j].rgbtBlue
                                         + image[i + 1][j - 1].rgbtBlue) / 4);
                    sumGreen = round(ceil(image[i][j].rgbtGreen
                                          + image[i][j - 1].rgbtGreen
                                          + image[i + 1][j].rgbtGreen
                                          + image[i + 1][j - 1].rgbtGreen) / 4);
                    sumRed = round(ceil(image[i][j].rgbtRed
                                        + image[i][j - 1].rgbtRed
                                        + image[i + 1][j].rgbtRed
                                        + image[i + 1][j - 1].rgbtRed) / 4);
                }

                else //top row middle pixel
                {
                    sumBlue = round(ceil(image[i][j].rgbtBlue
                                         + image[i][j - 1].rgbtBlue
                                         + image[i][j + 1].rgbtBlue
                                         + image[i + 1][j].rgbtBlue
                                         + image[i + 1][j - 1].rgbtBlue
                                         + image[i + 1][j + 1].rgbtBlue) / 6);
                    sumGreen = round(ceil(image[i][j].rgbtGreen
                                          + image[i][j - 1].rgbtGreen
                                          + image[i][j + 1].rgbtGreen
                                          + image[i + 1][j].rgbtGreen
                                          + image[i + 1][j - 1].rgbtGreen
                                          + image[i + 1][j + 1].rgbtGreen) / 6);
                    sumRed = round(ceil(image[i][j].rgbtRed
                                        + image[i][j - 1].rgbtRed
                                        + image[i][j + 1].rgbtRed
                                        + image[i + 1][j].rgbtRed
                                        + image[i + 1][j - 1].rgbtRed
                                        + image[i + 1][j + 1].rgbtRed) / 6);
                }

            }
            //Bottom row of image
            else if (i == height - 1)
            {
                if (j == 0) //left side pixel of bottom row
                {
                    sumBlue = round(ceil(image[i][j].rgbtBlue
                                         + image[i][j + 1].rgbtBlue
                                         + image[i - 1][j].rgbtBlue
                                         + image[i - 1][j + 1].rgbtBlue) / 4);
                    sumGreen = round(ceil(image[i][j].rgbtGreen
                                          + image[i][j + 1].rgbtGreen
                                          + image[i - 1][j].rgbtGreen
                                          + image[i - 1][j + 1].rgbtGreen) / 4);
                    sumRed = round(ceil(image[i][j].rgbtRed
                                        + image[i][j + 1].rgbtRed
                                        + image[i - 1][j].rgbtRed
                                        + image[i - 1][j + 1].rgbtRed) / 4);
                }

                else if (j == width - 1) //right side pixel of last row
                {
                    sumBlue = round(ceil(image[i][j].rgbtBlue
                                         + image[i][j - 1].rgbtBlue
                                         + image[i - 1][j].rgbtBlue
                                         + image[i - 1][j - 1].rgbtBlue) / 4);
                    sumGreen = round(ceil(image[i][j].rgbtGreen
                                          + image[i][j - 1].rgbtGreen
                                          + image[i - 1][j].rgbtGreen
                                          + image[i - 1][j - 1].rgbtGreen) / 4);
                    sumRed = round(ceil(image[i][j].rgbtRed
                                        + image[i][j - 1].rgbtRed
                                        + image[i - 1][j].rgbtRed
                                        + image[i - 1][j - 1].rgbtRed) / 4);
                }

                else //middle pixels of last row
                {
                    sumBlue = round(ceil(image[i][j].rgbtBlue
                                         + image[i][j - 1].rgbtBlue
                                         + image[i][j + 1].rgbtBlue
                                         + image[i - 1][j].rgbtBlue
                                         + image[i - 1][j - 1].rgbtBlue
                                         + image[i - 1][j + 1].rgbtBlue) / 6);
                    sumGreen = round(ceil(image[i][j].rgbtGreen
                                          + image[i][j - 1].rgbtGreen
                                          + image[i][j + 1].rgbtGreen
                                          + image[i - 1][j].rgbtGreen
                                          + image[i - 1][j - 1].rgbtGreen
                                          + image[i - 1][j + 1].rgbtGreen) / 6);
                    sumRed = round(ceil(image[i][j].rgbtRed
                                        + image[i][j - 1].rgbtRed
                                        + image[i][j + 1].rgbtRed
                                        + image[i - 1][j].rgbtRed
                                        + image[i - 1][j - 1].rgbtRed
                                        + image[i - 1][j + 1].rgbtRed) / 6);
                }

            }

            else
            {
                if (j == 0) //left side of image
                {
                    sumBlue = round(ceil(image[i][j].rgbtBlue
                                         + image[i - 1][j].rgbtBlue
                                         + image[i + 1][j].rgbtBlue
                                         + image[i][j + 1].rgbtBlue
                                         + image[i - 1][j + 1].rgbtBlue
                                         + image[i + 1][j + 1].rgbtBlue) / 6); //6 pixels surrounding the left side of the image
                    sumGreen = round(ceil(image[i][j].rgbtGreen
                                          +  image[i - 1][j].rgbtGreen
                                          +  image[i + 1][j].rgbtGreen
                                          +  image[i][j + 1].rgbtGreen
                                          +  image[i - 1][j + 1].rgbtGreen
                                          +  image[i + 1][j + 1].rgbtGreen) / 6);
                    sumRed = round(ceil(image[i][j].rgbtRed
                                        +  image[i - 1][j].rgbtRed
                                        +  image[i + 1][j].rgbtRed
                                        +  image[i][j + 1].rgbtRed
                                        +  image[i - 1][j + 1].rgbtRed
                                        +  image[i + 1][j + 1].rgbtRed) / 6);
                }

                //Right side of image
                else if (j == width - 1)
                {
                    sumBlue = round(ceil(image[i][j].rgbtBlue
                                         + image[i - 1][j].rgbtBlue
                                         + image[i + 1][j].rgbtBlue
                                         + image[i][j - 1].rgbtBlue
                                         + image[i - 1][j - 1].rgbtBlue
                                         + image[i + 1][j - 1].rgbtBlue) / 6);
                    sumGreen = round(ceil(image[i][j].rgbtGreen
                                          +  image[i - 1][j].rgbtGreen
                                          +  image[i + 1][j].rgbtGreen
                                          +  image[i][j - 1].rgbtGreen
                                          +  image[i - 1][j - 1].rgbtGreen
                                          +  image[i + 1][j - 1].rgbtGreen) / 6);
                    sumRed = round(ceil(image[i][j].rgbtRed
                                        +  image[i - 1][j].rgbtRed
                                        +  image[i + 1][j].rgbtRed
                                        +  image[i][j - 1].rgbtRed
                                        +  image[i - 1][j - 1].rgbtRed
                                        +  image[i + 1][j - 1].rgbtRed) / 6);
                }

                else //middle pixels of middle rows
                {
                    //calculate for blue pixels
                    sumBlue = round(ceil(image[i - 1][j - 1].rgbtBlue
                                         + image[i - 1][j].rgbtBlue
                                         + image[i - 1][j + 1].rgbtBlue
                                         + image[i][j - 1].rgbtBlue
                                         + image[i][j].rgbtBlue
                                         + image[i][j + 1].rgbtBlue
                                         + image[i + 1][j - 1].rgbtBlue
                                         + image[i + 1][j].rgbtBlue
                                         + image[i + 1][j + 1].rgbtBlue) / 9);
                    //calculate for green pixels
                    sumGreen = round(ceil(image[i - 1][j - 1].rgbtGreen
                                          + image[i - 1][j].rgbtGreen
                                          + image[i - 1][j + 1].rgbtGreen
                                          + image[i][j - 1].rgbtGreen
                                          + image[i][j].rgbtGreen
                                          + image[i][j + 1].rgbtGreen
                                          + image[i + 1][j - 1].rgbtGreen
                                          + image[i + 1][j].rgbtGreen
                                          + image[i + 1][j + 1].rgbtGreen) / 9); // 9 pixels surrounding the middle one
                    //calculate for red pixels
                    sumRed = round(ceil(image[i - 1][j - 1].rgbtRed
                                        + image[i - 1][j].rgbtRed
                                        + image[i - 1][j + 1].rgbtRed
                                        + image[i][j - 1].rgbtRed
                                        + image[i][j].rgbtRed
                                        + image[i][j + 1].rgbtRed
                                        + image[i + 1][j - 1].rgbtRed
                                        + image[i + 1][j].rgbtRed
                                        + image[i + 1][j + 1].rgbtRed) / 9);
                }
            }

            //assign temp values with the calculated values
            temp[i][j].rgbtBlue = round((sumBlue));
            temp[i][j].rgbtGreen = round((sumGreen));
            temp[i][j].rgbtRed = round((sumRed));

        }
    }

    //copies values from temporary table and assigns to original image
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            //assiging temp value to original image
            image[j][i].rgbtBlue = temp[j][i].rgbtBlue;
            image[j][i].rgbtGreen = temp[j][i].rgbtGreen;
            image[j][i].rgbtRed = temp[j][i].rgbtRed;
        }
    }




}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-05
    • 1970-01-01
    • 1970-01-01
    • 2020-11-05
    • 2021-08-11
    • 1970-01-01
    • 2013-11-07
    • 2011-07-29
    相关资源
    最近更新 更多