Pull to refresh

Comments 16

Резюмируя. Для пары практически не отличающихся изображений оценка совпадения 0,45. Произвольная пара изображений даёт ложно-положительный ответ в 0,15.

однако  гиф изображения не подходят для классификации ввиду сильного сжатия
Они-то как раз и показывают реальное совпадение/различие (0,02), которое даёт алгоритм. А когда затем стали использовать не по одному изображению, а цветные изображения, бинаризованные способом из первой статьи, то фактически стали сравнивать крупные «низкочастотные» пятна на них. Вот и выросло «совпадение» с 0,02 до 0,15.
Согласен с VDG.
Странный подход, по идее любой машинный классификатор изображений должен удовлетворительно справляться с классификацией того, что легко классифицирует человек(иначе не стоит и браться). В данном случае, человеку похожие изображения сопоставить не то что не проблема, а даже не задача. Даже простой попиксельный подсчёт дистанции даст однозначный результат.
Если я правильно понял, волна начинает формироваться из области с интенсивностью выше некоторого порога, по идее это для двух случайно зашумлённых изображений даст, в общем случае, случайный результат, который в волнах высших порядков может быть сойдётся к чему-то более-менее общему. Звучит как-то не очень надёжно.
Вывод, предложенный метод не работает.(А как он может работать вообще, без хотя какой-то нормализации входных данных, мне не понятно.)
Что вы подразумеваете под «попиксельным подсчетом дистанции»?
Переводим изображение в RGB и по каждому каналу для каждого пикселя считаем корень из модуля разности квадратов значений для двух изображений(либо просто модуль разности). Полученные таким образом расстояния по всем каналам и всем пикселям просто складываем. Получаем одно число, которое тем меньше, чем изображения более схожи.
Для большей ясности. Изображение 1 назовём P1, А изображение 2 — P2.
Пиксель имеет координаты XYС, где C это цветовой канал R,G или B, а X Y это положение. Ниже алгоритм на питоне, в предположении, что изображение это трёхмерный массив.
def PicDist(P1,P2)
  sum =0
  for x in range(X):
    for y in range(Y):
      for C in ['R','G','B']:
        sum += sqrt(abs(P1[x][y][C]**2 - P2[x][y][C]**2))
return sum
gif-это 8 битное изображение, которое сдержит палитру цветов.Если взять пару немного отличающихся изображений, например с 15 и 14 тысячами цветов, и преобразовать их в 255-цветное gif изображение, палитры для одного и другого изображения будут различны.Ваш алгоритм «попиксельного подсчета дистанции» работать не будет, поскольку при обратном преобразовании из палитры gif-а в RGB изображения будут искажения цветов.
От чего же не будет? Специально только что попробовал(в GIMP). Взял RGB изображение из стандартных виндовых, сохранил как gif, открыл и преобразовал обратно в RGB. Искажения есть, но они небольшие. Разница между изображениями мизерная (Самое яркое искажение не больше 20 по каждому каналу, различимых глазом точек не много). Соответственно и расстояние будет небольшое. Как и должно для сильно схожих изображений. Поэтому должно сработать
Хорошо.Сфотографируйте два похожих объекта(не одинаковых, а похожих) преобразуйте их оба в гиф, потом преобразуйте их обратно в RGB, сравните их своей программой, и сообщите здесь.
image
image
image
тестовые изображения.
Тестовый код на питоне:
import pygame
import os
import numpy as np
#from math import sqrt

P1 = pygame.surfarray.array3d(pygame.image.load(os.path.join("Pictures","TestImage1.png")))
P2 = pygame.surfarray.array3d(pygame.image.load(os.path.join("Pictures","TestImage2.png")))
P3 = pygame.surfarray.array3d(pygame.image.load(os.path.join("Pictures","TestImage3.png")))

(R,G,B) = (0,1,2)
Sum12 = Sum13 = Sum23 = 0
for x in range(512):
    for y in range(512):
        for color in (R,G,B):
            Sum12 += abs(float(P1[x][y][color]) - float(P2[x][y][color]))
            Sum13 += abs(float(P1[x][y][color]) - float(P3[x][y][color]))
            Sum23 += abs(float(P2[x][y][color]) - float(P3[x][y][color]))
Norma = 255*3*(512**2)
N12 = Sum12/Norma
N13 = Sum13/Norma
N23 = Sum23/Norma

def makeMono(Array):
        New_Array = np.zeros(Array.shape)
        for x,row in enumerate(Array):
            for y,(R,G,B) in enumerate(row):
                New_Array[x][y] = int((0.299*R**2 + 0.587*G**2 + 0.114*B**2)**0.5)
        return New_Array[:,:,0]

Pm1 = makeMono(P1)
Pm2 = makeMono(P2)
Pm3 = makeMono(P3)

SumM12 = SumM13 = SumM23 = 0
for x in range(512):
    for y in range(512):
        SumM12 += abs(float(Pm1[x][y]) - float(Pm2[x][y]))
        SumM13 += abs(float(Pm1[x][y]) - float(Pm3[x][y]))
        SumM23 += abs(float(Pm2[x][y]) - float(Pm3[x][y]))
Norma = 255*(512**2)
Nm12 = SumM12/Norma
Nm13 = SumM13/Norma
Nm23 = SumM23/Norma


Результаты при сохранении цвета N11,N12 и N23 (расстояния между соотв. изображениями):
N11 = 0.144
N12 = 0.191
N23 = 0.176
Не ахти, но два ближайшие показаны верно и это метод «в лоб»

Результаты при обесцвечивании Nm11,Nm12 и Nm23:
Nm11 = 0.141
Nm12 = 0.180
Nm23 = 0.152
Суть та же, результат верный. Метод элементарный «в лоб».
Если надо, могу исходные гифки выложить.
PS исправил ошибку в коде. N от Nm теперь почти не отличаются.
PSPS. Подскажите как это можно свернуть, чтоб простынёй не висело? ))
Я к чему, мой пример можно использовать как референс того, хуже чего работать не должно в принципе. И Gif — не Gif реально совершенно не важно.
Хорошо.Моя программа создает процент совпадения волновой-контурной памяти.При одинаковых изображениях процент совпадения равен 100%.Объясните пожалуйста, как можно использовать ваши цифры 0.141,0.180, и 0.152, и как их преобразовать в проценты? Я понял, что если изображения абсолютно похожи, ваша программa выдаст нули.Как найти процент совпадения изображений вашим способом?
как их преобразовать в проценты?
* 100
Наверно это неправильно, потому что если бы это было так, то для одинаковых картинок процент совпадения был бы 100%.Однако, процент совпадения одинаковых изображений равен нулю.Следовательно, правильной была бы формула (1-число)*100.В этом случае мы получаем следующий результат.Для 0.141 получаем (1-0.141)*100=85,9%, для 0.180 получаем (1-0.180)*100=82%, а для 0.152 мы получаем(1-0.152)*100=84,8%.Это как то подозрительно одинаково как для разных картинок, так и для одинаковых.Следовательно, на 100 умножать неправильно.
Картинки именно что похожи(третью специально по цветам подбирал), поэтому результат близкий. Ниже пример непохожей картинки, результат явный.
если для «похожих» мера сходства около 85%, то от них с явно непохожей -2… 5%.
Я не говорю что простое определение расстояния хороший метод классификации(см. «похожие» картинки), но он даёт стабильный и предсказуемый результат, при этом метод простой как грабли. К тонкостям качества картинки он тоже умерено чувствителен(считай робастный). Поэтому задумывая классификатор и распознавание изображений, надо добиваться результата не хуже.
image
Четвёртое изображение специально контрастное прошлым.
Результаты:
N14 = 1.021
N24 = 0.97
N34 = 0.95
Nm14 = 0.290
Nm24 = 0.266
Nm34 = 0.216

Хм. NumPy умеет в векторизованные операции. Первые 3 цикла заменяются строкой наподобие [N1,N2,N3] = np.average(np.abs(np.subtract(a,b)),axis=(0,1)) / 255 и т.д., это будет работать быстрее.

Не вопрос, но это надо было подумать)) В данном конкретном случае скорость безразлична. Плюс так любой, в том числе не знакомый с питоном, разберётся что именно тут написано.
Но да, можно оптимизировать.
Sign up to leave a comment.

Articles