Пишем бота для игры «Найди отличие»


    Не так давно я наткнулся на игру, в которую играл много лет назад. Я думаю, многие при поиске отличий ломали себе глаза долгое время. Сегодня я решил пройти её еще раз, но проходить её с 0 мне было, честно говоря, лень. Поэтому я решил написать себе помощника. В статье будет рассказано одно из решений, не наилучшее, но самое понятное для новичков. Итак, начнем.

    Писал я всё на python 2.7
    Использовалась библиотека PIL

    from PIL import Image, ImageDraw
    


    Далее необходимо описать все функции и методы, которые мы будем использовать, для того, чтобы всем был понятен дальнейший код.

    image1 = Image.open("1.jpg")
    

    Так мы открываем нужный нам файл.

    pix1 = image1.load()
    

    Записываем в pix1 цвета всех пикселов картинки. Теперь по координате пикселя мы можем получить его цвет.

    draw = ImageDraw.Draw(ANS)
    

    Создание инструмента для рисования.

    image1.size
    

    Возвращает пару (ширина и высота картинки).

    draw.ellipse((x, y), (255, 255, 255)) 
    

    Рисование белой точки по заданным координатам.

    ANS.save("ans.png", "PNG")
    

    Сохранение изображения в формате PNG. Если не указан полный путь, то сохраняется в папку с исполняемой программой.

    del draw
    

    Удаление инструмента «draw».

    Приступим к главному…

    Откроем файлы, которые мы хотим сравнивать.
    from PIL import Image, ImageDraw
    
    image1 = Image.open("1.jpg") # Картинка № 1
    image2 = Image.open("2.jpg") # Картинка № 2
    ANS = Image.open("1.jpg") # Результат
    


    Теперь создадим кисть и выгрузим из картинок все данные о цветах пикселов.
    from PIL import Image, ImageDraw
    
    image1 = Image.open("1.jpg") # Картинка № 1
    image2 = Image.open("2.jpg") # Картинка № 2
    ANS = Image.open("1.jpg") # Результат
    draw = ImageDraw.Draw(ANS)
    pix1 = image1.load()
    pix2 = image2.load()
    


    Необходимо определить размеры изображений. Так как они могут немного различаться, то возьмем минимальное из них, для того, чтобы не обратиться к несуществующим пикселам.
    from PIL import Image, ImageDraw
    
    image1 = Image.open("1.jpg") # Картинка № 1
    image2 = Image.open("2.jpg") # Картинка № 2
    ANS = Image.open("1.jpg") # Результат
    draw = ImageDraw.Draw(ANS)
    pix1 = image1.load()
    pix2 = image2.load()
    width = min(image1.size[0], image2.size[0])
    height = min(image1.size[1], image2.size[1])
    


    Осталось последнее. Будем перебирать пикселы и считать разность их значений.
    from PIL import Image, ImageDraw
    
    image1 = Image.open("2_1.jpg")
    image2 = Image.open("2_2.jpg")
    ANS = Image.open("2_1.jpg") 
    draw = ImageDraw.Draw(ANS)
    pix1 = image1.load()
    pix2 = image2.load()
    width = min(image1.size[0], image2.size[0])
    height = min(image1.size[1], image2.size[1])
    eps = 30
    for i in range(width):
    	for j in range(height):
    		dx1 = pix1[i, j][0] - pix2[i, j][0]
    		dx2 = pix1[i, j][1] - pix2[i, j][1]
    		dx3 = pix1[i, j][2] - pix2[i, j][2]
    		draw.point((i, j), (abs(dx1), abs(dx2), abs(dx3))) # Зарисовываем ответ разницей пикселов наших картинок по модулю.
    ANS.save("ans.jpg", "JPEG")
    del draw
    





















    Если немного подправить код.
    Метки:
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 55
    • +15
      Я всё понимаю, но это не бот даже близко. Бот понятия не имеет о ресурсах игры. Если бы вы скармливали приложению саму игру — было бы интереснее.

      И да, для игры-сравнения из разряда «чуть под другим углом» это и близко не прокатит.
      • +2
        Как результат с PNG? А то алгоритм хорошо находит артефакты от JPEG. Кстати, если совместить глазами картинку как для просмотра стереопар, то отличия очень легко находятся :)
        • 0
          У меня не получается. Совмещаю, совмещаю…
          • 0
            Попробуйте искать на изображениях характерные точки и совмещать картинки по ним. Например, детектор Харриса(Harris corner detector):
            docs.opencv.org/doc/tutorials/features2d/trackingmotion/harris_detector/harris_detector.html
            undergraduate.csse.uwa.edu.au/units/CITS4240/Lectures/tracking.pdf
            Как с этим функционалом на питоне — не могу сказать, но из академических соображений можно попробовать реализовать самостоятельно:)
            • +2
              Да это из пушки по воробьям, гораздо быстрее и эффективнее дихотомия сдвигов по x и y с оптимизацией среднеквадратичной разницы интенсивности значений пикселов оригинального и «выровненного» изображения. И код к этой идее будет ненамного длиннее моего описания на русском :)
            • 0
              А вообще неплохо бы автору измерить качество поиска отличий в зависимости от степени сжатия одного изображения относительно другого (красвый 3D-plot бы был). Ведь пока никаких качественных оценок этого «бота» не приведено, кроме странных картинок. :-)
            • +8
              Почему просто не XOR-ить одно изображение с другим?
              • 0
                Спасибо, попробую.
                • +6
                  Как-то так получается — у меня не получилось полностью совместить исходные изображения, поэтому видны контуры:
                  image
                  • +4
                    классный детектор контуров! :D
                    • +1
                      Ну это не совсем оно; картинки-то две, так что «контуры» будут в зависимости от того как они сдивнуты.

                      Вот сам баловался, честный детектор контуров писал:

                      Скрытый текст
                      image


                      OpenCV — «наше все».
                      • 0
                        Красиво! Исходники открыты?
                        И ещё несколько вопросов:
                        1) Какое рабочее цветовое пространство? Границы определяются для каждого цветового канала по отдельности или есть какой-то «интегральный» цвет? Не похоже на обычный перевод в тона серого.
                        2) Какой критерий «граничности» использовался? А почему границы «мягкие», это вероятностная оценка наличия границы в точке?

                        Немного занудства: насколько я понимаю писали Вы всё-таки детектор границ, т.к. контур это нечто другое.
                        • 0
                          Исходники чуть позже открою, возможно сделаю пост про нелинейные фильтры, довольно много материала накопилось.

                          1) Цветовое пространство входа — Grayscale (интенсивность), выхода — RGB, где за каждым каналом закреплены определенные пороги точности соответствия условию границы, синий — самый точный.
                          2) критерий — расхождение точек исходного изображения и деконволюции от гаусс блюра исходного изображения. Вероятностей как таковых не считается.

                          Занудство верное. Дальше по синему каналу уже обсчитываю контуры методом OpenCV. Некоторые границы не попадают в точные пороги и приходится думать брать другие каналы или нет, чтобы получить связный контур. Но эту часть еще не закончил, так что пока да, скорее нахождение границ.
              • +10
                Когда я хочу поиграть в ImageDiff, то включаю Mathematica. Понятно для новичков и писать недолго. Примерно так:

                результат:

                При желании можно координаты блобов вывести (центры масс, например)…
              • +2
                Кстати, не в тему питона, но сравнения таких вот картинок. Кто знаком со стереокартинками. Я когда-то для себя нашел способ очень быстро находить отличия в таких вот картинках. Как известно (да и по принципу) наш мозг определяет блеск, как разницу в каком-то участке изображения в левом и правом глазе. То есть совмещаем два изображения в одно (у кого не сильно хорошо получается — уменьшаем масштаб страницы), и видим блестящие части изображения. В свое время соревновались в такой игре и люди не могли понять, как я так быстро нахожу отличия :) А для меня они просто блестят! :)
                • 0
                  О, собрат по скиллу! )) Я тоже не так давно для себя открыл такой вариант) Действительно чертовски быстро получается. Фактически, совместил картинки, пробежал глазами по всей площади чтобы мозг настроился полноценно, и всё — видишь все «выбивающиеся» места.
                  • –1
                    Блеск вообще то — отражение света. А ваш метод выявляет артефакты — несовпадающие места при стереопросмотре будут иметь отличную от основного изображения глубину. Если ваш мозг воспринимает это как блеск, возможно вам следует обратится к врачу.

                    А так да, метод эффективен.
                    • НЛО прилетело и опубликовало эту надпись здесь
                      • +2
                        Зачем так к доктору отсылать то? У меня 2 глаза и все работает отлично. Можно и в интернете немного по теме почитать, если в детстве занимательных книг не читали. Вот отрывок: http://class-fizika.narod.ru/p1101.htm
                        А глубину будут иметь различную, если они, скажем так, со смещением на картинке. Но при этом, если цвет у них разный, то они тоже будут блестеть для нашего мозга.
                        • 0
                          Вот на примере указанной картинки — я легко вижу либо белый кристалл на черном фоне, либо черный фон… Блеска получить не могу, хотя 100% совместил :)
                          • 0
                            Ну там картинка конечно неахти выглядит…
                            • 0
                              проверил еще и перекрестным — тоже не блестит :))
                              • 0
                                Там картинка отсканированная в ужасном качестве. У меня была книга с таким рисунком, там все намного лучше. Найдите в другом месте нормальную :)
                                • 0
                                  www.plam.ru/phisika/zanimatelnaja_fizika_kniga_1/p11.php
                                  во всем инете только такой вариант картинки.
                                  • НЛО прилетело и опубликовало эту надпись здесь
                                    • 0
                                      И как, блестит? У меня медленно и «волной» переключается с белого на черный…
                                      • НЛО прилетело и опубликовало эту надпись здесь
                                        • +2
                                          Принцип блестящего участка точно такой же. На какой-то поверхности в нужной точке одним глазом Вы видите светлый участок, а в другой глаз уже не попадает отражение «светила» и он темный. Просто обычно это всего лишь небольшой участок, а не целая картинка, так что тут она выглядит странно. Гораздо «блестящее» выглядят небольшие участки с разным цветом на двух картинках.
                    • +3
                      Мне бы стыдно было выкладывать результат с зайцем.
                      По нему найти отличия сложнее чем по оригиналу.

                      Комментарии — как всегда лучше статьи.
                      • +18
                        Как страшно жить!

                        $ composite image1.png image2.png -compose difference  difference.png
                        


                        • +10
                          да во всех графических редакторах есть различные режимы смешивания слоев, в том числе и метод различий, но только линуксоиды пришли со своим консольным фотошопом и все опошлили. Человек же сейчас осознает свою ненужность
                          • +4
                            Человек же сейчас осознает свою ненужность
                            Воистину, Линукс полностью воплощает светлые идеалы технофашизма!
                      • +3
                        8 отличий на картинке с курицей —
                        показать
                        это восемь ножек паука?
                        • 0
                          Так точно, капитан!
                        • +1
                          Народ, вы всё делаете неправильно. В человека встроен отличный хардварный детектор различий. Кладём картинки рядом горизонтально, наводим каждый глаз на отдельную картинку (или перекрёстно, или параллельно) — и все отличия сразу начинают «мерцать», потому что мозг не может свести эти области.

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

                          Ну вот попробуйте:

                          • 0
                            Уже который раз пытаюсь совместить две картинки в одну — не удаётся. Не удавалось и в статье про упражнение для глаз с кружками. На каком расстоянии держать голову от холста, как долго смотреть?
                            • 0
                              Надо немного уменьшить масштаб в браузере, если настолько большие не получается свести. Расстояние… У меня 13 дюймов экран, расстояние до него около 40 см.
                              • +2
                                палец поставьте посередине и смотрите на него, отводя от экрана. как только появится 3 изображение в центре, попытайтесь сфокусироваться на нем. у меня тоже не получалось долго, потом вдруг и получилось спустя год после последней неудачной попытки.
                                • +1
                                  Если расматриваете параллельно (левым глазом — левое изобрежение, правым — правое), то необходимо, чтобы расстояние между одинаковыми точками на паре (здесь 400 пикселей) было меньше расстояния между зрачками. Если рассматриваете перекрёстно, то при должной тренировке расстояние может быть достаточно большим (впрочем, если в упор разглядывать Full-HD стерепару, то перспектива будет мешаться).

                                  P.S. Параллельно смотреть так и научился, сколько ни пытался. Перекрёстно совмещаю совершенно без проблем.
                                  • 0
                                    Всегда смотрел параллельным :) Сегодня первый раз посмотрел перекрестным. Правда параллельным (при небольшом размере картинки) я могу свести за 1-2 секунды изображение, а вот параллельным чуть дольше. При параллельном глаза разводятся от начального положения, при перекрестном наоборот сводятся.
                                    • 0
                                      Перекрестным мне лично сложнее значительно сфокусироваться. Надо сперва совместить изображения, без фокусировки, потом просто подождать, пока мозг подкрутит резкость, не расслабляя сведения.
                                      • 0
                                        Вот именно поэтому и у меня дольше происходит фокусировка :)
                                        • 0
                                          Кстати, лайфхак как научиться сводить и перекрещивать — используйте москитную сетку. Я так в детстве научился, сперва случайно, потом осознанно.
                                          Цель — расслабить глаза и «поймать» сетку в фокус. Через некоторое время это делается легко.
                                          При этом, если расслаблять глаза — сетка получается «висит» ближе чем края двери/окна (которые тоже при этом в фокусе), если перекрещивать — висит «дальше». прикольно при этом еще попытаться рукой потрогать :)
                                          • +1
                                            и еще момент — при расслаблении, ловится практически только на одном расстоянии, «свободном»;
                                            при скрещивании — можно на разном удалении поймать.

                                            плюс навыков — потом это можно использовать для гимнастики глаз, что ITшникам полезно крайне.
                                            • 0
                                              На счет москитной сетки, я чуть другое место приспособил — потолок автомобиля. Откидываешь на сиденье назад и смотришь, а там симметрично расположенные точки. Две рядом стоящие накладываются друг на друга, потом дальше разводим глаза и теперь смещаются еще на точку дальше и так далее, пока дальше глаза уже не можешь развести.
                                          • 0
                                            После минутной тренировки перекрестным способом стал обоими способами за 2 секунды сводить изображение.
                                    • +2
                                      Разноцветные банты и узор на зелёной ленте сразу заметил, а вот пока не «свёл» глаза и не увидел «мерцание», не обращал внимание на то, что у одного зайца есть пальцы на лапах, а у другого — нет!
                                      Вердикт: способ отлично работает :)

                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.