7
votes

Comment trouver rectangle de différence entre deux images

J'ai deux images de la même taille. Quelle est la meilleure façon de trouver le rectangle dans lequel ils diffèrent. Évidemment, je pourrais passer à travers l'image 4 fois dans différentes directions, mais je me demande s'il y a un moyen plus facile.

Exemple:

 première image

 second image

 différence


4 commentaires

Les arrière-plans sont-ils exactement la même chose?


Oui, j'essaie de trouver le plus petit rectangle en dehors de laquelle tout est pareil.


Vous pouvez soustraire les images (les matrices) les unes des autres - partout où vous ne recevez pas de zéro, ils sont différents. Passer ce matrice à un algorithme qui calcule la somme de toutes les lignes et colonnes (passant de l'extérieur à l'intérieur) jusqu'à ce qu'elle trouve une valeur qui a une valeur non zéro devrait vous donner le rectangle rouge.


Une bibliothèque intéressante pourrait être Aforge. Après avoir soustraire les images, vous pouvez utiliser ses capacités de traitement de blob: aforgenet.com/framework/features/ blobs_processing.html , voir aussi cette question connexe: Stackoverflow.com/questions/1162669/...


7 Réponses :


2
votes

Je ne pense pas qu'il y ait un moyen plus facile.

En fait, cela va simplement être un (très) rares lignes de code, donc à moins que vous ne trouviez une bibliothèque qui vous fait directement que vous ne trouverez pas de manière plus courte.


0 commentaires

4
votes

Une approche naïve serait de commencer à l'origine et de travailler en ligne par ligne, colonne par colonne. Comparez chaque pixel, gardant la note du plus haut, le plus à gauche, la plus à droite et la baste-botte, à partir duquel vous pouvez calculer votre rectangle. Il y aura des cas où cette approche de réussite unique serait plus rapide (c'est-à-dire où il y a une très petite zone différente)


0 commentaires

0
votes

Je ne pense pas qu'il puisse y avoir quelque chose de mieux que de rechercher de manière exhaustive de chaque côté pour le premier point de différence dans cette direction. À moins que, c'est-à-dire que vous savez un fait que, d'une manière ou d'une autre, contrainte l'ensemble des points de différence.


0 commentaires

3
votes

Le traitement de l'image comme celui-ci coûte cher, il y a beaucoup de bits à regarder. Dans les applications réelles, vous avez presque toujours besoin de filtrer l'image pour vous débarrasser des artefacts induits par des captures d'image imparfaites.

Une bibliothèque commune utilisée pour ce type de bits Whacking est OpenCV, il tire parti des instructions de processeur dédiées disponibles pour le faire rapidement. Il existe plusieurs wrappers .NET disponibles pour cela, Emgu est l'un d'entre eux .


1 commentaires

Parler d'artefacts Donc, si je fais Ce aura des mauvaises tailles? Parce que si vous utilisez mon code et hie hies les 2 premières photos, vous le verrez qu'Ippuyez presque la hauteur mais la largeur foirée



0
votes

Voici donc ici la voie facile si vous savez utiliser Lockbit :)

        Bitmap originalBMP = new Bitmap(pictureBox1.ImageLocation);
        Bitmap changedBMP = new Bitmap(pictureBox2.ImageLocation);

        int width = Math.Min(originalBMP.Width, changedBMP.Width),
            height = Math.Min(originalBMP.Height, changedBMP.Height),

            xMin = int.MaxValue,
            xMax = int.MinValue,

            yMin = int.MaxValue,
            yMax = int.MinValue;

        var originalLock = originalBMP.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, originalBMP.PixelFormat);
        var changedLock = changedBMP.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, changedBMP.PixelFormat);

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                //generate the address of the colour pixel
                int pixelIdxOrg = y * originalLock.Stride + (x * 4);
                int pixelIdxCh = y * changedLock.Stride + (x * 4);


                if (( Marshal.ReadByte(originalLock.Scan0, pixelIdxOrg + 2)!= Marshal.ReadByte(changedLock.Scan0, pixelIdxCh + 2))
                    || (Marshal.ReadByte(originalLock.Scan0, pixelIdxOrg + 1) != Marshal.ReadByte(changedLock.Scan0, pixelIdxCh + 1))
                    || (Marshal.ReadByte(originalLock.Scan0, pixelIdxOrg) != Marshal.ReadByte(changedLock.Scan0, pixelIdxCh))
                    )
                {
                    xMin = Math.Min(xMin, x);
                    xMax = Math.Max(xMax, x);

                    yMin = Math.Min(yMin, y);
                    yMax = Math.Max(yMax, y);
                }
            }
        }

        originalBMP.UnlockBits(originalLock);
        changedBMP.UnlockBits(changedLock);

        var result = changedBMP.Clone(new Rectangle(xMin, yMin, xMax - xMin, yMax - yMin), changedBMP.PixelFormat);

        pictureBox3.Image = result;


0 commentaires

1
votes

idée:

Considérez une image en tant que tableau 2D avec chaque élément de tableau sous forme de pixel de l'image. Par conséquent, je dirais que la différenciation de l'image n'est rien d'autre que la différenciation de la matrice 2D.

idée est de simplement numériser à travers la largeur des éléments de la matrice et trouver l'endroit où il y a une différence de valeur de pixels. Si l'exemple [X, Y] coordonnées des deux matrices 2D est différent, notre logique de recherche de rectangle commence. Plus tard sur les rectangles seraient utilisés pour corriger le dernier tampon de cadre mis à jour.

Nous devons rechercher les limites des rectangles pour les différences et si une différence se trouve dans la limite du rectangle, puis la limite être augmenté de la largeur ou de la hauteur en fonction du type de balayage fabriqué.

considère que j'ai numérisé la largeur de la matrice 2D et j'ai trouvé un endroit où il existe une coordonnée qui est différente dans les deux Les matrices 2D, je vais créer un rectangle avec la position de départ comme [x-1, y-1] et avec la largeur et la hauteur comme 2 et 2 respectivement. Veuillez noter que la largeur et la hauteur font référence au nombre de pixels.

par exemple: info rect: X = 20 Y = 35 W = 26 H = 23

I.e largeur du rectangle commence de coordonner [20, 35] -> [20, 35 + 26 - 1]. Peut-être que lorsque vous trouvez le code, vous pourrez peut-être mieux le comprendre.

Il existe également des possibilités qu'il existe des rectangles plus petits à l'intérieur d'un plus grand rectangle que vous avez trouvé, nous devons donc éliminer les plus petits rectangles de notre référence. parce qu'ils ne veulent rien dire pour nous sauf qu'ils occupent mon espace précieux !!

La logique ci-dessus serait utile dans le cas de la mise en œuvre du serveur VNC, où il y aurait un besoin de rectangles qui dénote des différences dans l'image que est actuellement pris. Ces rectangles pourraient être envoyés dans le réseau sur le client VNC qui peut corriger les rectangles de la copie locale de la mémoire tampon de cadre qu'il possède ainsi l'affichage de la carte d'affichage du client VNC.

PS:

Je vais attacher le code dans lequel j'ai mis en place mon propre algorithme. Je demanderais aux téléspectateurs de commenter des erreurs ou un réglage de la performance. Je demanderais également aux téléspectateurs de commenter n'importe quel meilleur algorithme qui rendrait la vie plus simple.

Code:

Classe: xxx

différence d'image de classe: xxx

Description:

Il y aurait une fonction nommée xxx

qui fait le travail de trouver des différences dans les images et de renvoyer une liste lieded d'objets. Les objets ne sont rien d'autre que les rectangles.

Il y a une fonction principale qui fait le travail de tester l'algorithme.

Il y a 2 échantillons d'images passées dans le code dans la fonction principale, elles sont rien que la "baseframe" et "capture d'écran" créant ainsi l'image résultante nommée "résultat".

Je ne possède pas la réputation souhaitée pour poster l'image résultante qui serait très intéressante.

Il y a un blog qui fournirait la sortie différence d'image < / p>


0 commentaires

3
votes

Si vous voulez un Un simple rectangle fort>, utilisez INT.MAXValue pour le seuil.

using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace diff_images
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            var filename1 = @"Gelatin1.PNG";
            var filename2 = @"Gelatin2.PNG";

            var diff = new ImageDiffUtil(filename1, filename2);
            var diffRectangles = diff.GetDiffRectangles(8);

            var img3 = Image.FromFile(filename2);
            Pen redPen = new Pen(Color.Red, 1);
            var padding = 3;
            using (var graphics = Graphics.FromImage(img3))
            {
                diffRectangles
                    .ToList()
                    .ForEach(rect =>
                    {
                        var largerRect = new Rectangle(rect.X - padding, rect.Y - padding, rect.Width + padding * 2, rect.Height + padding * 2);
                        graphics.DrawRectangle(redPen, largerRect);
                    });
            }

            var pb1 = new PictureBox()
            {
                Image = Image.FromFile(filename1),
                Left = 8,
                Top = 8,
                SizeMode = PictureBoxSizeMode.AutoSize
            };

            var pb2 = new PictureBox()
            {
                Image = Image.FromFile(filename2),
                Left = pb1.Left + pb1.Width + 16,
                Top = 8,
                SizeMode = PictureBoxSizeMode.AutoSize
            };

            var pb3 = new PictureBox()
            {
                Image = img3,
                Left = pb2.Left + pb2.Width + 16,
                Top = 8,
                SizeMode = PictureBoxSizeMode.AutoSize
            };

            Controls.Add(pb1);
            Controls.Add(pb2);
            Controls.Add(pb3);
        }
    }
}


0 commentaires