Сравнить две картинки

Язык Visual Basic на платформе .NET.

Модераторы: Ramzes, Sebas

ofolfa
Начинающий
Начинающий
 
Сообщения: 24
Зарегистрирован: 11.12.2008 (Чт) 12:41

Сравнить две картинки

Сообщение ofolfa » 30.04.2009 (Чт) 18:21

Есть две задачи для работы с картинками.
1. Подскажите, пожалуйста, как можно сравнить две картинки?
2. И как можно найти координаты картинки в картинке?

Сделал попиксельно, но процесс немного тормозит, в смысле по времени. В инет нашел один вариант, но он почему-то не всегда работает.

Данный код быстрее сравнивает две картинки, в чем может быть проблема что с некоторыми картинками не работает?
Код: Выделить всё
Public Function compareBitmap(ByVal b1 As Bitmap, ByVal b2 As Bitmap)
        If b1.Width <> b2.Width OrElse b1.Height <> b2.Height Then
            Return False
        End If

        If b1.PixelFormat <> b2.PixelFormat Then
            Return False
        End If

        Dim bytes As Integer
        If b1.PixelFormat = Imaging.PixelFormat.Format32bppArgb Then
            bytes = b1.Width * b1.Height * 4
        Else
            Return False
        End If

        Dim result As Boolean = True
        Dim b1bytes(bytes - 1) As Byte
        Dim b2bytes(bytes - 1) As Byte

        Dim bmd1 As Imaging.BitmapData = b1.LockBits(New Rectangle(0, 0, b1.Width - 1, b1.Height - 1), Imaging.ImageLockMode.ReadOnly, b1.PixelFormat)
        Dim bmd2 As Imaging.BitmapData = b2.LockBits(New Rectangle(0, 0, b2.Width - 1, b2.Height - 1), Imaging.ImageLockMode.ReadOnly, b2.PixelFormat)

        System.Runtime.InteropServices.Marshal.Copy(bmd1.Scan0, b1bytes, 0, bytes)
        System.Runtime.InteropServices.Marshal.Copy(bmd2.Scan0, b2bytes, 0, bytes)

        For n As Integer = 0 To bytes - 1
            If b1bytes(n) <> b2bytes(n) Then
                result = False
                Exit For
            End If
        Next

        b1.UnlockBits(bmd1)
        b2.UnlockBits(bmd2)

        Return result
    End Function

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Сравнить две картинки

Сообщение Nord777 » 30.04.2009 (Чт) 19:43

в чем может быть проблема что с некоторыми картинками не работает
b1.PixelFormat = Imaging.PixelFormat.Format32bppArgb :?:
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

ofolfa
Начинающий
Начинающий
 
Сообщения: 24
Зарегистрирован: 11.12.2008 (Чт) 12:41

Re: Сравнить две картинки

Сообщение ofolfa » 01.05.2009 (Пт) 14:29

Точно, как я сам не заметил :) Думаю проблема была именно в этом. Спасибо, буду проверять.
А на счет
2. И как можно найти координаты картинки в картинке?

никто ничего не может сказать?

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Сравнить две картинки

Сообщение Nord777 » 01.05.2009 (Пт) 18:33

2. И как можно найти координаты картинки в картинке?

никто ничего не может сказать?
Наверно может. Только ты сначала обьясни, что это означает :)
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

Williams
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1280
Зарегистрирован: 06.05.2008 (Вт) 18:35
Откуда: System.Reflection.Williams (увидел себя в зеркале :))

Re: Сравнить две картинки

Сообщение Williams » 01.05.2009 (Пт) 20:52

Наверное автор хочет выудить фрагмент изображения, соответствующий другому изображению :roll:
И вы думаете, что вас оставят в живых после прочтения этого поста?

ofolfa
Начинающий
Начинающий
 
Сообщения: 24
Зарегистрирован: 11.12.2008 (Чт) 12:41

Re: Сравнить две картинки

Сообщение ofolfa » 01.05.2009 (Пт) 22:59

Есть две картинки. Одна большая, вторая маленькая. Нужно найти координаты маленькой картинки в большой картинке.
К примеру маленькая картинке окно, большая картинка дом. Нужно найти где находиться окно в доме :), координаты х, у.

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Сравнить две картинки

Сообщение Nord777 » 01.05.2009 (Пт) 23:04

А в чём загвоздка? Это всего лишь алгоритм. Причем несложный.
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

ofolfa
Начинающий
Начинающий
 
Сообщения: 24
Зарегистрирован: 11.12.2008 (Чт) 12:41

Re: Сравнить две картинки

Сообщение ofolfa » 01.05.2009 (Пт) 23:47

Вот меня и интересует алгоритм. Я знаю только как проверить попиксельно. Но думаю, что есть варианты и получше.

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Сравнить две картинки

Сообщение Nord777 » 01.05.2009 (Пт) 23:51

Я знаю только как проверить попиксельно. Но думаю, что есть варианты и получше.
Нет. Только попиксельно.

Add:
А что ты понимаешь под словом "попиксельно"?
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

ofolfa
Начинающий
Начинающий
 
Сообщения: 24
Зарегистрирован: 11.12.2008 (Чт) 12:41

Re: Сравнить две картинки

Сообщение ofolfa » 02.05.2009 (Сб) 1:21

Понимаю так

Код: Выделить всё
Public Function findImgPos(ByVal mainImg As Bitmap, ByVal findImg As Bitmap, ByVal startPos As System.Drawing.Point) As Point
        Dim fColor As Color = findImg.GetPixel(0, 0)
        Dim x, y As UInteger

        For x = startPos.X To mainImg.Width - 2 - findImg.Width
            For y = startPos.Y To mainImg.Height - 2 - findImg.Height
                If mainImg.GetPixel(x, y) = fColor Then
                    Dim x1, y1 As UInteger
                    Dim break As Boolean
                    break = False
                    For x1 = x To x + findImg.Width - 1
                        For y1 = y To y + findImg.Height - 1
                            If mainImg.GetPixel(x1, y1) <> findImg.GetPixel(x1 - x, y1 - y) Then
                                break = True
                                Exit For
                            End If
                        Next
                        If break = True Then Exit For
                    Next
                    If (x1 - x) = findImg.Width And (y1 - y) = findImg.Height Then
                        Return new Point(x, y)
                    End If
                End If
            Next
        Next
        Return New Point(0, 0)
    End Function


Спасибо за помощь!

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Сравнить две картинки

Сообщение Nord777 » 02.05.2009 (Сб) 18:16

Если скорость критична, то лучше использовать не GetPixel, а массив.
Функция для получения массива из картинки:
Код: Выделить всё
   Private Function GetArrayFromBitmap(ByVal SrcBmp As Bitmap) As Integer(,)
      Dim gch As GCHandle
      Dim tmpBmp As Bitmap
      Dim W% = SrcBmp.Width, H% = SrcBmp.Height, Stride% = SrcBmp.Width * 4

      'массив под изображение 
      Dim BmpArray(H - 1, W - 1) As Integer 'Integer

      gch = GCHandle.Alloc(BmpArray, GCHandleType.Pinned)
      tmpBmp = New Bitmap(W, H, Stride, PixelFormat.Format32bppRgb, gch.AddrOfPinnedObject)

      'отобразим картинку на массив
      Using G As Graphics = Graphics.FromImage(tmpBmp)
         G.DrawImage(SrcBmp, 0, 0)
      End Using
      tmpBmp.Dispose(): gch.Free()

      ' В результате в массиве BmpArray(,) содержатся данные в формате 32bpp
      Return BmpArray
   End Function
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

ofolfa
Начинающий
Начинающий
 
Сообщения: 24
Зарегистрирован: 11.12.2008 (Чт) 12:41

Re: Сравнить две картинки

Сообщение ofolfa » 02.05.2009 (Сб) 18:51

Спасибо, хороший вариант.

Маленький вопрос. Можно ли как-то высоты и ширину поменять местами?
Сейчас первым в массиве идет высота, а потом ширина. У меня все наоборот. Будет немного неудобно. Конечно не проходя еще раз по циклу.

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Сравнить две картинки

Сообщение Nord777 » 02.05.2009 (Сб) 19:36

Можно ли как-то высоты и ширину поменять местами?
Не надо так делать.
Данные массива именно так и располагаются в памяти.
Лучше измени алгоритм.
Например:
Код: Выделить всё
   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
      Dim BigArr(,) As Integer = GetArrayFromBitmap(BigBmp)
      Dim SmallArr(,) As Integer = GetArrayFromBitmap(SmallBmp)

      For row As Integer = 0 To BigBmp.Height - SmallBmp.Height - 1
         For col As Integer = 0 To BigBmp.Width - SmallBmp.Width - 1
            If BigArr(row, col) <> SmallArr(0, 0) Then Continue For

            For row1 As Integer = row To row + SmallBmp.Height - 1
               For col1 As Integer = col To col + SmallBmp.Width - 1
                  If BigArr(row1, col1) <> SmallArr(row1 - row, col1 - col) Then GoTo g01
               Next
            Next
            MsgBox("Картинка найдена." & vbCrLf & "Её координаты: " & col & ", " & row) : Exit Sub
g01:
         Next
      Next
      MsgBox("Картинка Не найдена")
   End Sub
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

ofolfa
Начинающий
Начинающий
 
Сообщения: 24
Зарегистрирован: 11.12.2008 (Чт) 12:41

Re: Сравнить две картинки

Сообщение ofolfa » 02.05.2009 (Сб) 20:04

Спасибо большое за помощь!

ofolfa
Начинающий
Начинающий
 
Сообщения: 24
Зарегистрирован: 11.12.2008 (Чт) 12:41

Re: Сравнить две картинки

Сообщение ofolfa » 03.05.2009 (Вс) 0:38

Подскажите, пожалуйста, что нужно менять, что бы эта функция работа для 24 битного изображения?
И что вообще означает 32 битное изображение? Это 24 битное плюс поддержка прозрачности?
Код: Выделить всё
Public Function compareBitmap(ByVal b1 As Bitmap, ByVal b2 As Bitmap)
        If b1.Width <> b2.Width OrElse b1.Height <> b2.Height Then
            Return False
        End If

        If b1.PixelFormat <> b2.PixelFormat Then
            Return False
        End If

        Dim bytes As Integer
        If b1.PixelFormat = Imaging.PixelFormat.Format32bppArgb Then
            bytes = b1.Width * b1.Height * 4
        Else
            Return False
        End If

        Dim result As Boolean = True
        Dim b1bytes(bytes - 1) As Byte
        Dim b2bytes(bytes - 1) As Byte

        Dim bmd1 As Imaging.BitmapData = b1.LockBits(New Rectangle(0, 0, b1.Width - 1, b1.Height - 1), Imaging.ImageLockMode.ReadOnly, b1.PixelFormat)
        Dim bmd2 As Imaging.BitmapData = b2.LockBits(New Rectangle(0, 0, b2.Width - 1, b2.Height - 1), Imaging.ImageLockMode.ReadOnly, b2.PixelFormat)

        System.Runtime.InteropServices.Marshal.Copy(bmd1.Scan0, b1bytes, 0, bytes)
        System.Runtime.InteropServices.Marshal.Copy(bmd2.Scan0, b2bytes, 0, bytes)

        For n As Integer = 0 To bytes - 1
            If b1bytes(n) <> b2bytes(n) Then
                result = False
                Exit For
            End If
        Next

        b1.UnlockBits(bmd1)
        b2.UnlockBits(bmd2)

        Return result
    End Function

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Сравнить две картинки

Сообщение Nord777 » 03.05.2009 (Вс) 1:29

Format32bppRgb
Указывает, что форматом отводится 32 бит на точку: по 8 бит на красный, зеленый и синий каналы. Оставшиеся 8 бит не используются

Format32bppArgb
Указывает, что форматом отводится 32 бита на точку: по 8 бит на красный, зеленый и синий каналы, а также альфа-канал.


Код: Выделить всё
   Public Function compareBitmap(ByVal b1 As Bitmap, ByVal b2 As Bitmap) As Boolean
      If b1.Width <> b2.Width OrElse b1.Height <> b2.Height Then Return False
      If b1.PixelFormat <> b2.PixelFormat Then Return False

      Dim W% = b1.Width, H% = b1.Height, R As New Rectangle(0, 0, W, H)
      Dim bmd1 As BitmapData = b1.LockBits(R, ImageLockMode.ReadOnly, b1.PixelFormat)
      Dim bmd2 As BitmapData = b2.LockBits(R, ImageLockMode.ReadOnly, b2.PixelFormat)

      Dim stride% = bmd1.Stride
      Dim b1bytes(H * stride - 1) As Byte
      Dim b2bytes(H * stride - 1) As Byte


      Marshal.Copy(bmd1.Scan0, b1bytes, 0, b1bytes.Length)
      Marshal.Copy(bmd2.Scan0, b2bytes, 0, b2bytes.Length)
      b1.UnlockBits(bmd1) : b2.UnlockBits(bmd2)

      Dim BytesPerPixel% = stride \ W
      Dim RowAddr%

      For row As Integer = 0 To H - 1
         For col As Integer = 0 To W * BytesPerPixel - 1
            If b1bytes(RowAddr + col) <> b2bytes(RowAddr + col) Then Return False
         Next
         RowAddr += stride
      Next

      Return True
   End Function
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

ofolfa
Начинающий
Начинающий
 
Сообщения: 24
Зарегистрирован: 11.12.2008 (Чт) 12:41

Re: Сравнить две картинки

Сообщение ofolfa » 03.05.2009 (Вс) 14:31

Да, я тоже так думал. Оказывается что не совсем так или функция не совершенная, она у меня и для 32 битных изображений не совсем качественно работает, как я уже описал. Думал это из-за 32 и 24 бита. А нет, ошибка в самом алгоритме где-то ((

Может кто-то подскажет другой способ? Желательно дял 24битных изображений, можно и 32, не смертельно.

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Сравнить две картинки

Сообщение Nord777 » 03.05.2009 (Вс) 17:08

Может кто-то подскажет другой способ? Желательно дял 24битных изображений, можно и 32, не смертельно.
Код работает. Проверял. Ошибка где то у тебя.
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

ofolfa
Начинающий
Начинающий
 
Сообщения: 24
Зарегистрирован: 11.12.2008 (Чт) 12:41

Re: Сравнить две картинки

Сообщение ofolfa » 03.05.2009 (Вс) 17:11

Сколько тестов проводил?
У меня работает. Но иногда выдает что картинки разные, хоть они абсолютно одинаковые.
Понять в чем проблема не могу. Если сравнить те же картинки просто попиксельно, то все ок.

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Сравнить две картинки

Сообщение Nord777 » 03.05.2009 (Вс) 17:16

Я правильно думаю, что ошибается на 24bit?
Мой код пробовал?
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

ofolfa
Начинающий
Начинающий
 
Сообщения: 24
Зарегистрирован: 11.12.2008 (Чт) 12:41

Re: Сравнить две картинки

Сообщение ofolfa » 05.05.2009 (Вт) 1:54

Да, ошибка именно с 24 битными изображениями, переделал все в 32, работает нормально.
Пробовал именно твой код, всеравно есть глюки, я думаю, что ошибка из-за формата, хотя могу ошибаться.
Спасибо большое за помощь. Вопросов больше нету.


Вернуться в Visual Basic .NET

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 69

    TopList