Question

Je dois mettre en œuvre Algorithme rétinex à échelle unique et rétinex multi-échelles en C#,
J'ai cherché un peu mais je n'ai trouvé aucun projet pratique ni article utile avec du code
Si j'ai bien compris, je devrais :

  1. Convertir RVB en YUV
  2. Flou l'image à l'aide du filtre de flou gaussien
  3. Utilisez I'(x, y) = 255*log10( I(x, y)/G(x, y) ) + 127,5
    I - est l'éclairage, G - le noyau gaussien, I' - l'image résultante
  4. Сonvertir YUV en RVB

Ce code ne fonctionne pas correctement

 public static Image<Bgr, byte> SingleScaleRetinex(this Image<Bgr, byte> img, int gaussianKernelSize, double sigma)
            {
                var radius = gaussianKernelSize / 2;
                var kernelSize = 2 * radius + 1;

                var ycc = img.Convert<Ycc, byte>();

                var sum = 0f;
                var gaussKernel = new float[kernelSize * kernelSize];
                for (int i = -radius, k = 0; i <= radius; i++, k++)
                {
                    for (int j = -radius; j <= radius; j++)
                    {
                        var val = (float)Math.Exp(-(i * i + j * j) / (sigma * sigma));
                        gaussKernel[k] = val;
                        sum += val;
                    }
                }
                for (int i = 0; i < gaussKernel.Length; i++)
                    gaussKernel[i] /= sum;

                var gray = new Image<Gray, byte>(ycc.Size);
                CvInvoke.cvSetImageCOI(ycc, 1);
                CvInvoke.cvCopy(ycc, gray, IntPtr.Zero);

                // Размеры изображения
                var width = img.Width;
                var height = img.Height;

                var bmp = gray.Bitmap;
                var bitmapData = bmp.LockBits(new Rectangle(Point.Empty, gray.Size), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

                unsafe
                {
                    for (var y = 0; y < height; y++)
                    {
                        var row = (byte*)bitmapData.Scan0 + y * bitmapData.Stride;
                        for (var x = 0; x < width; x++)
                        {
                            var color = row + x;

                            float val = 0;

                            for (int i = -radius, k = 0; i <= radius; i++, k++)
                            {
                                var ii = y + i;
                                if (ii < 0) ii = 0; if (ii >= height) ii = height - 1;

                                var row2 = (byte*)bitmapData.Scan0 + ii * bitmapData.Stride;
                                for (int j = -radius; j <= radius; j++)
                                {
                                    var jj = x + j;
                                    if (jj < 0) jj = 0; if (jj >= width) jj = width - 1;

                                    val += *(row2 + jj) * gaussKernel[k];

                                }
                            }

                            var newColor = 127.5 + 255 * Math.Log(*color / val);
                            if (newColor > 255)
                                newColor = 255;
                            else if (newColor < 0)
                                newColor = 0;
                            *color = (byte)newColor;
                        }
                    }
                }
                bmp.UnlockBits(bitmapData);

                CvInvoke.cvCopy(gray, ycc, IntPtr.Zero);
                CvInvoke.cvSetImageCOI(ycc, 0);

                return ycc.Convert<Bgr, byte>();

            }
Était-ce utile?

La solution

Regardez: http://www.fer.unizg.h/ipg/resources/color_concstancy

Ces algorithmes sont des modifications de l'algorithme de rétinex (avec une amélioration de la vitesse), bien que l'auteur leur a donné des noms amusants :)

Il y a un code source complet (C ++, mais il est écrit très bien).

Autres conseils

Désolé pour le nécro-posting, mais il semble qu'il y ait une erreur à l'étape 3 de votre procédure qui peut induire en erreur quelqu'un de passage.

Afin d'appliquer la correction, vous souhaitez diviser l'image source par une copie filtrée par Gauss, et non par le noyau gaussien lui-même.En gros, en pseudo-code :

I_filtered(x,y) = G(x,y) * I(x,y)
I'(x,y) = log(I(x,y) / I_filtered(x,y))

Et puis appliquez le casting de I'(x,y) au type numérique requis (uint8, comme je peux me référer au message original).

Plus d'informations sur ce sujet peuvent être trouvées dans ce papier:

Ri(x, y) = log(Ii(x, y)) − log(Ii(x, y) ∗ F(x, y))

Iiest l'image d'entrée sur le i-ième canal de couleur, Riest l'image de sortie Retinex sur le i -th canal et F est la fonction surround normalisée..

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top