【问题标题】:Image Processing: Noise Reduction using Vector Median Processing图像处理:使用矢量中值处理降噪
【发布时间】:2015-10-05 05:19:22
【问题描述】:

所以,我的任务是创建一个矢量中值过滤器来帮助清理嘈杂的图像。这背后的逻辑并不太复杂。首先,只是为了平衡支付领域,所有图像都作为 3d 值数组进入 java。红色、绿色和蓝色值存储在一种行/列情况中。所以它在引用像素值时就像这样:

[Color Component (Red, green, or blue)][Row][Col]

这将向您显示图像特定位置的确切像素值。我想象一个正方形,当做这些时类似于矩阵的东西。

所以...到过滤器..

来自一篇学术文章:“此过滤器通过在具有 RGB 值的目标像素上移动一个窗口 [a mask] 来执行非线性过滤,并将该像素的值重置为与另一个像素的距离之和最小的像素窗口中的像素。”

如果您没有做过任何图像处理工作,这可能看起来有些令人困惑,但实际上非常简单。您的蒙版本质上是一个框,它在图像中移动并创建一个具有预定约束大小的像素“邻域”(我通常使用 3x3 “邻域”,因此我将有 9 个值 - 就像我在下面的代码中一样。 )

要点是选择邻域中的目标像素 - 通常是中心(在本示例中,始终是中心)并根据周围像素计算它的值。非常简单,而且在消除图像中的噪点方面也非常令人印象深刻。

所以创建新像素值的逻辑是最重要的部分。获取“邻域”值相当容易,我也会将其包括在内,但我遇到的问题是我认为我没有正确计算逻辑。如上所述,逻辑比较每个“邻域”像素值彼此并创建每个像素相对于其余像素的距离的运行总和。运行总和为 LOWEST 的像素将成为目标像素的新值。

我遵循的步骤(带有代码示例):

  1. 获取邻域值:

            //First two for loops will travel through column and row of image array. 
            //The third will travel through the RGB values (This is 4 values because Transparency is also accounted for here.)
            for (int row = 1; row < imageInDimension.getHeight() - 1; row++) {
            for (int column = 1; column < imageInDimension.getWidth() - 1; column++) {
            for (int ColComp = 1; ColComp < 4; ColComp++) {
            //////////////////////////
            //The Neighborhood////////
            //////////////////////////
            int pixelNeighbors[] = new int[9];
            //Assign values to neighborhood
            pixelNeighbors[0] = OldImageTGRB[ColComp][column - 1][row - 1];
            pixelNeighbors[1] = OldImageTGRB[ColComp][column - 1][row];
            pixelNeighbors[2] = OldImageTGRB[ColComp][column - 1][row + 1];
            pixelNeighbors[3] = OldImageTGRB[ColComp][column][row - 1];
            pixelNeighbors[4] = OldImageTGRB[ColComp][column][row];
            pixelNeighbors[5] = OldImageTGRB[ColComp][column][row + 1];
            pixelNeighbors[6] = OldImageTGRB[ColComp][column + 1][row - 1];
            pixelNeighbors[7] = OldImageTGRB[ColComp][column + 1][row];
            pixelNeighbors[8] = OldImageTGRB[ColComp][column + 1][row + 1];
    
  2. 对“邻居”中的每个像素相对于“邻居”中的其他像素执行距离计算,并将每个值存储在运行总和中(此处使用绝对值,因为它是距离公式)

                //Calculate distances
                for (int i = 0; i < 8; i++) {
                    runningSumPixel0 += Math.abs(pixelNeighbors[0] - pixelNeighbors[i]);
                    runningSumPixel1 += Math.abs(pixelNeighbors[1] - pixelNeighbors[i]);
                    runningSumPixel2 += Math.abs(pixelNeighbors[2] - pixelNeighbors[i]);
                    runningSumPixel3 += Math.abs(pixelNeighbors[3] - pixelNeighbors[i]);
                    runningSumPixel4 += Math.abs(pixelNeighbors[4] - pixelNeighbors[i]);
                    runningSumPixel5 += Math.abs(pixelNeighbors[5] - pixelNeighbors[i]);
                    runningSumPixel6 += Math.abs(pixelNeighbors[6] - pixelNeighbors[i]);
                    runningSumPixel7 += Math.abs(pixelNeighbors[7] - pixelNeighbors[i]);
                    runningSumPixel8 += Math.abs(pixelNeighbors[8] - pixelNeighbors[i]);
                }
    
  3. 这就是我认为我要么让它太复杂要么搞乱逻辑的地方。我需要资助最低的运行总和并将目标像素设置为该值。我现在将每个单独的运行总和与所有值进行比较,并验证它是否是最低的。如果是最低的,则成为目标像素值。这是一篇很长的文章,我很抱歉。

                    //Determine lowest distance value and set target pixel to lowest distance value original value
                    if (runningSumPixel0 < runningSumPixel1 &
                            runningSumPixel0 < runningSumPixel2 &
                            runningSumPixel0 < runningSumPixel3 &
                            runningSumPixel0 < runningSumPixel4 &
                            runningSumPixel0 < runningSumPixel5 &
                            runningSumPixel0 < runningSumPixel6 &
                            runningSumPixel0 < runningSumPixel7 &
                            runningSumPixel0 < runningSumPixel8) {
                        System.out.println("Target set to o position");
                        newImageTRGB[ColComp][column][row] = pixelNeighbors[0];
    
                    } else if (runningSumPixel1 < runningSumPixel0 &
                            runningSumPixel1 < runningSumPixel2 &
                            runningSumPixel1 < runningSumPixel3 &
                            runningSumPixel1 < runningSumPixel4 &
                            runningSumPixel1 < runningSumPixel5 &
                            runningSumPixel1 < runningSumPixel6 &
                            runningSumPixel1 < runningSumPixel7 &
                            runningSumPixel1 < runningSumPixel8) {
                        System.out.println("Target set to 1 position");
                        newImageTRGB[ColComp][column][row] = pixelNeighbors[1];
    
                    } else if (runningSumPixel2 < runningSumPixel0 &
                            runningSumPixel2 < runningSumPixel1 &
                            runningSumPixel2 < runningSumPixel3 &
                            runningSumPixel2 < runningSumPixel4 &
                            runningSumPixel2 < runningSumPixel5 &
                            runningSumPixel2 < runningSumPixel6 &
                            runningSumPixel2 < runningSumPixel7 &
                            runningSumPixel2 < runningSumPixel8) {
                        System.out.println("Target set to 2 position");
                        newImageTRGB[ColComp][column][row] = pixelNeighbors[2];
    
                    } else if (runningSumPixel3 < runningSumPixel0 &
                            runningSumPixel3 < runningSumPixel1 &
                            runningSumPixel3 < runningSumPixel3 &
                            runningSumPixel3 < runningSumPixel4 &
                            runningSumPixel3 < runningSumPixel5 &
                            runningSumPixel3 < runningSumPixel6 &
                            runningSumPixel3 < runningSumPixel7 &
                            runningSumPixel3 < runningSumPixel8) {
                        System.out.println("Target set to 3 position");
                        newImageTRGB[ColComp][column][row] = pixelNeighbors[3];
    
                    } else if (runningSumPixel4 < runningSumPixel0 &
                            runningSumPixel4 < runningSumPixel2 &
                            runningSumPixel4 < runningSumPixel3 &
                            runningSumPixel4 < runningSumPixel1 &
                            runningSumPixel4 < runningSumPixel5 &
                            runningSumPixel4 < runningSumPixel6 &
                            runningSumPixel4 < runningSumPixel7 &
                            runningSumPixel4 < runningSumPixel8) {
                        System.out.println("Target set to 4 position");
                        newImageTRGB[ColComp][column][row] = pixelNeighbors[4];
    
                    } else if (runningSumPixel5 < runningSumPixel0 &
                            runningSumPixel5 < runningSumPixel2 &
                            runningSumPixel5 < runningSumPixel3 &
                            runningSumPixel5 < runningSumPixel4 &
                            runningSumPixel5 < runningSumPixel1 &
                            runningSumPixel5 < runningSumPixel6 &
                            runningSumPixel5 < runningSumPixel7 &
                            runningSumPixel5 < runningSumPixel8) {
                        System.out.println("Target set to 5 position");
                        newImageTRGB[ColComp][column][row] = pixelNeighbors[5];
    
                    } else if (runningSumPixel6 < runningSumPixel0 &
                            runningSumPixel6 < runningSumPixel2 &
                            runningSumPixel6 < runningSumPixel3 &
                            runningSumPixel6 < runningSumPixel4 &
                            runningSumPixel6 < runningSumPixel5 &
                            runningSumPixel6 < runningSumPixel1 &
                            runningSumPixel6 < runningSumPixel7 &
                            runningSumPixel6 < runningSumPixel8) {
                        System.out.println("Target set to 6 position");
                        newImageTRGB[ColComp][column][row] = pixelNeighbors[6];
    
                    } else if (runningSumPixel7 < runningSumPixel0 &
                            runningSumPixel7 < runningSumPixel2 &
                            runningSumPixel7 < runningSumPixel3 &
                            runningSumPixel7 < runningSumPixel4 &
                            runningSumPixel7 < runningSumPixel5 &
                            runningSumPixel7 < runningSumPixel6 &
                            runningSumPixel7 < runningSumPixel1 &
                            runningSumPixel7 < runningSumPixel8) {
                        System.out.println("Target set to 7 position");
                        newImageTRGB[ColComp][column][row] = pixelNeighbors[7];
    
                    } else if (runningSumPixel8 < runningSumPixel0 &
                            runningSumPixel8 < runningSumPixel2 &
                            runningSumPixel8 < runningSumPixel3 &
                            runningSumPixel8 < runningSumPixel4 &
                            runningSumPixel8 < runningSumPixel5 &
                            runningSumPixel8 < runningSumPixel6 &
                            runningSumPixel8 < runningSumPixel7 &
                            runningSumPixel8 < runningSumPixel1) {
                        System.out.println("Target set to 8 position");
                        newImageTRGB[ColComp][column][row] = pixelNeighbors[8];
    
                    }
                }
    
            }
        }
    
  4. 返回新图像。

我相当确定我的邻域是正确的,因为我使用相同的算法在不同的过滤器上找到邻域,并且它完美无缺。

问题:本质上,代码根本没有减少噪音。事实上,它对图像没有任何作用。这没有任何意义,因为理论上我正在改变每个像素值..

有什么建议吗?希望这不是一个特定的问题。提前致谢!

建议更新后的整个方法:

protected Image VMFilter (Image imageIn) {
        //Get Image Dimensions
        Dimension imageInDimension = getImageDimension(imageIn);

        //calculate total number of pixels
        double totalPixels = imageInDimension.getHeight() * imageInDimension.getWidth();

        //Move image into an array.."old image"
        int OldImageTGRB[][][] = pixelsArrayToTRGBArray(imageToPixelsArray(imageIn), imageInDimension);
        //Create new image where new values will be stored
        int newImageTRGB[][][] = pixelsArrayToTRGBArray(imageToPixelsArray(imageIn), imageInDimension);


        //////////////////////////////////
        //////////THE LOGIC///////////////
        //////////////////////////////////
        //Sort through oldImage TRGB and create the neighborhood from values
        for (int row = 1; row < imageInDimension.getHeight() - 1; row++) {
            for (int column = 1; column < imageInDimension.getWidth() - 1; column++) {
                //Will Cycle through the color components assigning values to the neighborhood
                for (int ColComp = 1; ColComp < 4; ColComp++) {

                    //////////////////////////
                    //The Neighborhood////////
                    //////////////////////////
                    int pixelNeighbors[] = new int[9];

                    //Assign values to neighborhood
                    pixelNeighbors[0] = OldImageTGRB[ColComp][column - 1][row - 1];
                    pixelNeighbors[1] = OldImageTGRB[ColComp][column - 1][row];
                    pixelNeighbors[2] = OldImageTGRB[ColComp][column - 1][row + 1];
                    pixelNeighbors[3] = OldImageTGRB[ColComp][column][row - 1];
                    pixelNeighbors[4] = OldImageTGRB[ColComp][column][row];
                    pixelNeighbors[5] = OldImageTGRB[ColComp][column][row + 1];
                    pixelNeighbors[6] = OldImageTGRB[ColComp][column + 1][row - 1];
                    pixelNeighbors[7] = OldImageTGRB[ColComp][column + 1][row];
                    pixelNeighbors[8] = OldImageTGRB[ColComp][column + 1][row + 1];

                    //Create running sum variables to keep track of distance calculation sums
                    int runningSumPixels[] = new int[9];


                    //Calculate distances
                    for (int i = 0; i < 9; i++) {
                        runningSumPixels[i] += Math.abs(pixelNeighbors[i] - pixelNeighbors[i]);
                    }

                    int iLow = Integer.MAX_VALUE;
                    int lowest = Integer.MAX_VALUE;

                    for (int i = 0; i < 9; ++i) {
                        if (runningSumPixels[i] < lowest) {
                            iLow = i;
                            lowest = runningSumPixels[i];
                        }
                        System.out.println("Old Value:" + newImageTRGB[ColComp][column][row]);
                        newImageTRGB[ColComp][column][row] = pixelNeighbors[iLow];
                        System.out.println("New Value:" + newImageTRGB[ColComp][column][row]);
                        }
                    }
                }
            }
        //Return new image..
        return pixelsArrayToImage(
                TRGBArrayToPixelsArray(newImageTRGB, imageInDimension), imageInDimension);
    }

【问题讨论】:

  • 如果您能准确地告诉我们您得到了令您惊讶的结果,那就太好了。还有一种更简单的方法来执行第 3 步,我会在找到问题后向您描述。
  • 警告! 上面的代码不计算向量中值。这是对分别计算每个通道的中位数的一种昂贵方式的尝试。向量中值需要使用每个像素的 RGB 值作为向量,并计算向量距离。

标签: java image-processing


【解决方案1】:

错误:在第 3 步 if 语句中,Java 逻辑 AND 运算符是 &amp;&amp;,而不是 &amp;

可能的错误: 在第 2 步循环中,在我看来应该允许 i 取值 8,将条件更改为 i &lt; 9 而不是 i &lt; 8

改进:您当前对第 3 步的实现非常幼稚(并且可能是错误的,因为 &lt; 而不是 &lt;= 运算符)。考虑这样做:

  • 将 9 个 runningSumPixel 变量替换为一个数组(如 pixelNeighbors);
  • 将步骤 3 替换为以下代码。

代码

int iLow, lowest = Integer.MAX_VALUE;

for (int i = 0; i < 9; ++i) {
    if (runningSumPixel[i] < lowest) {
        iLow = i;
        lowest = runningSumPixel[i];
}

newImageTRGB[ColComp][column][row] = pixelNeighbors[iLow];

比你的小一点,对吧? :)

【讨论】:

  • 哇!我怎么没看到。非常感谢你。不幸的是,这并没有改变结果。我忘了提到上面的问题,我会进行编辑,但基本上代码并没有减少噪音。事实上,它对图像没有任何作用。这没有任何意义,因为理论上我正在改变每个像素值..
  • 在哪里声明runningSumPixel 变量?这部分我不太确定。
  • 在循环之外的方法的开头。我将继续并包括上面的整个方法。注意我在此方法中提到的所有其他方法(例如 TRGBarrayToPixelArray)都可以正常工作,这也可能很有用。我在主代码的其他几个部分使用它们并且没有错误。
  • 您的严格小于比较 (&lt;),而不是 小于或等于 (&lt;=),只有在是邻域中一个且只有一个的最小值(即,如果有两个相等的距离,则没有一个会触发分配)。我会在下一次编辑中为你解决这个问题。
  • 那肯定做了一些事情!我现在得到了输出,但不是我所期望的。我必须确保这些是所涉及的唯一步骤,但我相当确定您的代码完全符合我的要求。非常感谢!
【解决方案2】:

我将您的代码转换为位图用例。

protected Bitmap VMFilter (Bitmap bitmap) {
        //Get Image Dimensions
        //Dimension imageInDimension = getImageDimension(imageIn);

        //calculate total number of pixels
        double totalPixels = bitmap.getWidth()* bitmap.getHeight(); //imageInDimension.getHeight() * imageInDimension.getWidth();
        int w = bitmap.getWidth(),h = bitmap.getHeight();

        //Move image into an array.."old image"
        int OldImageTGRB[][][] = bitmapToTRGBArray(bitmap);
        //Create new image where new values will be stored
        int[][][] newImageTRGB = new int[w][h][3];////pixelsArrayToTRGBArray(bitmap);


        //////////////////////////////////
        //////////THE LOGIC///////////////
        //////////////////////////////////
        //Sort through oldImage TRGB and create the neighborhood from values
        int nearbyWindow = 10;
        for (int row = nearbyWindow; row < bitmap.getWidth() -nearbyWindow ; row++) {
            for (int column = nearbyWindow; column < bitmap.getHeight()-nearbyWindow ; column++) {
                //Will Cycle through the color components assigning values to the neighborhood
                for (int ColComp = 0; ColComp < 3; ColComp++) {

                    //////////////////////////
                    //The Neighborhood////////
                    //////////////////////////
                    int totalNeighbors = nearbyWindow * nearbyWindow;

                    int pixelNeighbors[] = new int[totalNeighbors];

                    
                    for(int i=0;i<totalNeighbors;i++){
                        pixelNeighbors[i] = OldImageTGRB[row-1][column-1][ColComp];
                    }

                    //Create running sum variables to keep track of distance calculation sums
                    int runningSumPixels[] = new int[totalNeighbors];


                    //Calculate distances
                    for (int i = 0; i < totalNeighbors; i++) {
                        runningSumPixels[i] += Math.abs(pixelNeighbors[i] - pixelNeighbors[ColComp]);
                    }

                    int iLow = Integer.MAX_VALUE;
                    int lowest = Integer.MAX_VALUE;

                    for (int i = 0; i < totalNeighbors; ++i) {
                        if (runningSumPixels[i] < lowest) {
                            iLow = i;
                            lowest = runningSumPixels[i];
                        }
                        //System.out.println("Old Value:" + newImageTRGB[ColComp][column][row]);
                        newImageTRGB[row][column][ColComp] = pixelNeighbors[iLow];
                        //System.out.println("New Value:" + newImageTRGB[ColComp][column][row]);
                    }
                }
            }
        }
        //Return new image..
        return pixelsArrayToBitmap(newImageTRGB, w,h, bitmap);
    }

【讨论】:

  • 请注意,OP 的代码是不正确的,并且不做向量中值:它进行每通道计算,而不是使用 RGB 值作为向量并计算向量距离。
  • 感谢@CrisLuengo 让我知道。你能为我提供正确的向量中位数算法吗?
猜你喜欢
  • 2020-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-14
  • 2018-06-23
相关资源
最近更新 更多