Алгоритм сокращения красных глаз

Мне нужно реализовать уменьшение эффекта "красных глаз" для приложения, над которым я работаю.

Googling в основном предоставляет ссылки на коммерческие конечные продукты.

Знаете ли вы хороший алгоритм сокращения красных глаз, который можно использовать в приложении GPL?

Ответ 1

Я опоздал на вечеринку, но для будущих искателей я использовал следующий алгоритм для личного приложения, которое я написал.

Прежде всего, область для уменьшения выбирается пользователем и передается методу уменьшения эффекта красных глаз в качестве центральной точки и радиуса. Метод проходит через каждый пиксель в радиусе и выполняет следующий расчет:

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

Мне очень нравятся результаты этого, потому что они сохраняют интенсивность цвета, а это означает, что световое отражение глаза не уменьшается. (Это означает, что глаза сохраняют "живой" вид.)

Ответ 2

отличная библиотека для поиска глаз openCV. он очень богат функциями обработки изображений. см. также этот документ с названием "Автоматическое обнаружение красных глаз" от Илии В. Сафонова.

Ответ 3

Сначала вам нужно найти глаза! Стандартным способом было бы запустить детектор кромок, а затем преобразование Хафа, чтобы найти два круга одинакового размера, но могут быть более простые алгоритмы для простого поиска кластеров с красными пикселями.

Затем вам нужно решить, что заменить их, если в изображении достаточно зеленых/синих данных, вы можете просто игнорировать красный канал.

OpenCV - очень хорошая бесплатная библиотека для обработки изображений, она может быть излишней для того, что вы хотите - но имеет множество примеров и очень активное сообщество. Вы также можете искать алгоритмы отслеживания объектов, отслеживание цветного объекта в сцене - очень похожая и общая проблема.

Ответ 4

Если никто больше не приступает к более прямому ответу, вы всегда можете скачать исходный код для GIMP и посмотреть, как они это делают.

Ответ 5

Самый простой алгоритм, и все же тот, который очень эффективен, должен был бы обнулить R тройки RGB для интересующей области.

Красный исчезает, но сохраняются другие цвета.

Дальнейшее расширение этого алгоритма может включать обнуление значения R только для троек, где красный цвет является доминирующим (R > G и R > B).

Ответ 7

Проект с открытым исходным кодом Paint.NET имеет реализацию на С#.

Ответ 8

Вот решение для реализации 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);

Ответ 9

Это более полная реализация ответа, предоставленного Бенри:

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