红眼降噪算法

42

我需要在我正在开发的应用程序中实现红眼缩减功能。

谷歌搜索主要提供商业终端用户产品的链接。

你知道一个好的红眼缩减算法,可以在GPL应用程序中使用吗?

10个回答

44

虽然我来晚了,但是对于未来的搜索者,我为我编写的个人应用程序使用了以下算法。

首先,用户选择要减少的区域,并将其作为中心点和半径传递给红眼减少方法。该方法循环遍历半径内的每个像素,并执行以下计算:

//Value of red divided by average of blue and green:
Pixel pixel = image.getPixel(x,y);
float redIntensity = ((float)pixel.R / ((pixel.G + pixel.B) / 2));
if (redIntensity > 1.5f)  // 1.5 because it gives the best results
{
    // reduce red to the average of blue and green
    bm.SetPixel(i, j, Color.FromArgb((pixel.G + pixel.B) / 2, pixel.G, pixel.B));
}

我非常喜欢这个结果,因为它保持了颜色的强度,这意味着眼睛的光反射没有减少。(这意味着眼睛保持了它们的“活力”外观。)


您还可以在单击点处使用“魔法棒”选择工具,并由用户提供最大半径。 - rafaelcastrocouto

7

一个很好的查找眼睛的库是OpenCV。 它拥有丰富的图像处理功能。 另外,可以查看这篇标题为“自动红眼检测”的论文,作者为Ilia V. Safonov。


6

首先,您需要找到眼睛!标准的方法是运行边缘检测器,然后使用霍夫变换找到两个相同大小的圆,但是可能有更简单的算法可以仅查找红色像素的聚类。

然后,您需要决定要用什么替换它们,假设图像中有足够的绿色/蓝色数据,您可以简单地忽略红色通道。

OpenCV是一款非常好用的免费图像处理库,它可能超出了您所需的范围,但具有许多示例和非常活跃的社区。您还可以搜索对象跟踪算法,跟踪场景中的彩色对象是一个非常相似且常见的问题。


4
如果没有其他更直接的答案,你可以下载GIMP的源代码来查看它们是如何做的。

3

最简单的算法,同时也是非常有效的一种算法,就是将感兴趣区域RGB三元组的R值归零。

红色消失了,但其他颜色保留下来。

这个算法的进一步扩展可能涉及只将主导颜色为红色的三元组的R值归零(R > G且R > B)。


3

3

我认为源代码已经无法获取了。 - John T

2
这是对Benry提供答案的更完整实现:
  using SD = System.Drawing;

  public static SD.Image ReduceRedEye(SD.Image img, SD.Rectangle eyesRect)
  {
     if (   (eyesRect.Height > 0)
         && (eyesRect.Width > 0)) {
        SD.Bitmap bmpImage = new SD.Bitmap(img);
        for (int x=eyesRect.X;x<(eyesRect.X+eyesRect.Width);x++) {
           for (int y=eyesRect.Y;y<(eyesRect.Y+eyesRect.Height);y++) {
              //Value of red divided by average of blue and green:
              SD.Color pixel = bmpImage.GetPixel(x,y);
              float redIntensity = ((float)pixel.R / ((pixel.G + pixel.B) / 2));
              if (redIntensity > 2.2f)
              {
                 // reduce red to the average of blue and green
                 bmpImage.SetPixel(x, y, SD.Color.FromArgb((pixel.G + pixel.B) / 2, pixel.G, pixel.B));
                 pixel = bmpImage.GetPixel(x,y); // for debug
              }
           }
        }
        return (SD.Image)(bmpImage);
     }
     return null;
  }

2
这里是Java实现的解决方案。
public void corrigirRedEye(int posStartX, int maxX, int posStartY, int maxY, BufferedImage image) {
    for(int x = posStartX; x < maxX; x++) {
        for(int y = posStartY; y < maxY; y++) {

            int c = image.getRGB(x,y);
            int  red = (c & 0x00ff0000) >> 16;
            int  green = (c & 0x0000ff00) >> 8;
            int  blue = c & 0x000000ff;

            float redIntensity = ((float)red / ((green + blue) / 2));
            if (redIntensity > 2.2) {
                Color newColor = new Color(90, green, blue);
                image.setRGB(x, y, newColor.getRGB());
            }


        }
    }
}

这是从一个应用程序,如open cv中检测到的两个矩形中检索到的参数(这应该涉及眼睛位置的矩形)

int posStartY = (int) leftEye.getY();

    int maxX = (int) (leftEye.getX() + leftEye.getWidth());
    int maxY = (int) (leftEye.getY() + leftEye.getHeight());

    this.corrigirRedEye(posStartX, maxX, posStartY, maxY, image);

    // right eye

    posStartX = (int) rightEye.getX();
    posStartY = (int) rightEye.getY();

    maxX = (int) (rightEye.getX() + rightEye.getWidth());
    maxY = (int) (rightEye.getY() + rightEye.getHeight());

    this.corrigirRedEye(posStartX, maxX, posStartY, maxY, image);

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接