Алгоритм пошуку подібних зображень


83

Мені потрібен алгоритм, який може визначити, чи є два зображення "подібними", і розпізнає подібні візерунки кольору, яскравості, форми тощо. Мені можуть знадобитися деякі вказівки щодо того, які параметри людський мозок використовує для "класифікації" зображень. ..

Я розглядав відповідність на основі hausdorff, але це, здається, головним чином для відповідності трансформованих об'єктів та візерунків фігури.


У цьому іншому подібному питанні є кілька хороших відповідей: stackoverflow.com/questions/25977/…
blak

2
багато "міг" і "чудес". Хтось спробує всі ці пропозиції, і знаєш, що найкраще?
john ktejik

Відповіді:


60

Я зробив щось подібне, розкладаючи зображення на підписи за допомогою вейвлет-перетворення .

Мій підхід полягав у тому, щоб вибрати найбільш значущі n коефіцієнтів з кожного трансформованого каналу та записати їх розташування. Це було зроблено шляхом сортування списку (потужність, місце розташування) кортежів за абс (потужність). Подібні зображення матимуть подібність у тому, що вони матимуть значні коефіцієнти в тих самих місцях.

Я виявив, що найкраще перетворити зображення на формат YUV, що ефективно дозволяє вам схожість ваги за формою (Y-канал) та кольором (UV-канали).

Ви можете знайти мою реалізацію вищезазначеного в mactorii , над якою , на жаль, я працював не так сильно, як мав би :-)

Інший метод, який деякі мої друзі застосували з напрочуд хорошими результатами, - це просто зменшити розмір вашого зображення, скажімо, 4х4 пікселя та зберегти, що є вашим підписом. Наскільки схожі 2 зображення, можна підрахувати, скажімо, обчисливши відстань між Манхеттеном між 2 зображеннями, використовуючи відповідні пікселі. У мене немає деталей про те, як вони виконували зміну розміру, тому вам, можливо, доведеться пограти з різними алгоритмами, доступними для цього завдання, щоб знайти підходящий.


7
Метод зміни розміру до 4х4 - це чудова ідея (не те, що ваш метод теж не чудовий), але перший простіший.
Алікс Аксель

@freespace, не могли б ви пояснити це "обчислення відстані Манхеттена між 2 зображеннями, використовуючи відповідні пікселі"
Амбіка

1
@Ambika: обробляйте колір кожного пікселя як вектор довжиною 3 і обчислюйте відстань Манхеттена між відповідними пікселями на зображеннях, що порівнюються. Це дає вам 4 відстані до Манхеттена. Як ви вибираєте з цього єдиний мір, вирішувати вам. Найбільш очевидним є їх підсумовування.
простір

45

pHash може вас зацікавити.

перцептивний хеш n. відбиток пальця аудіо-, відео- чи графічного файлу, який математично базується на аудіо- або візуальному вмісті, що міститься всередині. На відміну від криптографічних хеш-функцій, які покладаються на лавинний ефект невеликих змін у вхідних даних, що призводять до кардинальних змін у виведенні, перцептивні хеші "близькі" один до одного, якщо вхідні дані візуально або слухово схожі.


8
Щойно перевірив веб-сайт pHash. На даний момент вони мають на своєму сайті цю функцію, яка дозволяє завантажувати два зображення, і вона повідомляє, схожі вони чи ні. Я спробував близько 10 зображень, які були подібними, і 10, які не були. На жаль, рівень успіху був не таким вражаючим.
rodrigo-silveira

2
pHash насправді досить суворий, можливо, ви захочете використовувати "ahash" або середній хеш, який, як правило, менш жорсткий. Ви можете знайти реалізацію python тут github.com/JohannesBuchner/imagehash/blob/master/…
Рохіт,

13

Я використовував SIFT для повторного виявлення того самого об'єкта на різних зображеннях. Це дійсно потужно, але досить складно і може бути надмірним. Якщо зображення мають бути досить схожими, деякі прості параметри, засновані на різниці між цими двома зображеннями, можуть сказати вам досить багато. Деякі вказівки:

  • Нормалізуйте зображення, тобто зробіть середню яскравість обох зображень однаковою, розрахувавши середню яскравість обох і масштабуючи найяскравіше вниз відповідно до раціону (щоб уникнути відсікання на найвищому рівні), особливо якщо вас більше цікавить форма, ніж колір.
  • Сума різниці кольорів щодо нормалізованого зображення на канал.
  • знайти краї на зображеннях і виміряти відстань між пікселями краю на обох зображеннях. (для форми)
  • Розділіть зображення на дискретну область і порівняйте середній колір кожної області.
  • Обмежте зображення на одному рівні (або наборі) рівнів і підрахуйте кількість пікселів, де отримані чорно-білі зображення відрізняються.

чи можете ви вказати на код, який використовує сітчасті плоди для обчислення подібності зображення?
mrgloom

Вибачте, я впевнений, що є загальнодоступний код, але жодного, про який я знаю. На цьому сайті є кілька прикладів. Наприклад тут: stackoverflow.com/questions/5461148 / ...
jilles де Віт

У Accord Framework для .Net ( accord-framework.net ) є декілька чудових класів для роботи з SURF, BagOfVisualWords, виявленням кутів Харріса тощо з безліччю різних ядер та алгоритмів кластеризації.
dynamichael

6

Моя лабораторія також мала вирішити цю проблему, і ми використовували Tensorflow. Ось повна реалізація програми для візуалізації схожості зображень.

Підручник з векторизації зображень для обчислення подібності див. На цій сторінці . Ось Python (знову дивіться пост для повного робочого процесу):

from __future__ import absolute_import, division, print_function

"""

This is a modification of the classify_images.py
script in Tensorflow. The original script produces
string labels for input images (e.g. you input a picture
of a cat and the script returns the string "cat"); this
modification reads in a directory of images and 
generates a vector representation of the image using
the penultimate layer of neural network weights.

Usage: python classify_images.py "../image_dir/*.jpg"

"""

# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================

"""Simple image classification with Inception.

Run image classification with Inception trained on ImageNet 2012 Challenge data
set.

This program creates a graph from a saved GraphDef protocol buffer,
and runs inference on an input JPEG image. It outputs human readable
strings of the top 5 predictions along with their probabilities.

Change the --image_file argument to any jpg image to compute a
classification of that image.

Please see the tutorial and website for a detailed description of how
to use this script to perform image recognition.

https://tensorflow.org/tutorials/image_recognition/
"""

import os.path
import re
import sys
import tarfile
import glob
import json
import psutil
from collections import defaultdict
import numpy as np
from six.moves import urllib
import tensorflow as tf

FLAGS = tf.app.flags.FLAGS

# classify_image_graph_def.pb:
#   Binary representation of the GraphDef protocol buffer.
# imagenet_synset_to_human_label_map.txt:
#   Map from synset ID to a human readable string.
# imagenet_2012_challenge_label_map_proto.pbtxt:
#   Text representation of a protocol buffer mapping a label to synset ID.
tf.app.flags.DEFINE_string(
    'model_dir', '/tmp/imagenet',
    """Path to classify_image_graph_def.pb, """
    """imagenet_synset_to_human_label_map.txt, and """
    """imagenet_2012_challenge_label_map_proto.pbtxt.""")
tf.app.flags.DEFINE_string('image_file', '',
                           """Absolute path to image file.""")
tf.app.flags.DEFINE_integer('num_top_predictions', 5,
                            """Display this many predictions.""")

# pylint: disable=line-too-long
DATA_URL = 'http://download.tensorflow.org/models/image/imagenet/inception-2015-12-05.tgz'
# pylint: enable=line-too-long


class NodeLookup(object):
  """Converts integer node ID's to human readable labels."""

  def __init__(self,
               label_lookup_path=None,
               uid_lookup_path=None):
    if not label_lookup_path:
      label_lookup_path = os.path.join(
          FLAGS.model_dir, 'imagenet_2012_challenge_label_map_proto.pbtxt')
    if not uid_lookup_path:
      uid_lookup_path = os.path.join(
          FLAGS.model_dir, 'imagenet_synset_to_human_label_map.txt')
    self.node_lookup = self.load(label_lookup_path, uid_lookup_path)

  def load(self, label_lookup_path, uid_lookup_path):
    """Loads a human readable English name for each softmax node.

    Args:
      label_lookup_path: string UID to integer node ID.
      uid_lookup_path: string UID to human-readable string.

    Returns:
      dict from integer node ID to human-readable string.
    """
    if not tf.gfile.Exists(uid_lookup_path):
      tf.logging.fatal('File does not exist %s', uid_lookup_path)
    if not tf.gfile.Exists(label_lookup_path):
      tf.logging.fatal('File does not exist %s', label_lookup_path)

    # Loads mapping from string UID to human-readable string
    proto_as_ascii_lines = tf.gfile.GFile(uid_lookup_path).readlines()
    uid_to_human = {}
    p = re.compile(r'[n\d]*[ \S,]*')
    for line in proto_as_ascii_lines:
      parsed_items = p.findall(line)
      uid = parsed_items[0]
      human_string = parsed_items[2]
      uid_to_human[uid] = human_string

    # Loads mapping from string UID to integer node ID.
    node_id_to_uid = {}
    proto_as_ascii = tf.gfile.GFile(label_lookup_path).readlines()
    for line in proto_as_ascii:
      if line.startswith('  target_class:'):
        target_class = int(line.split(': ')[1])
      if line.startswith('  target_class_string:'):
        target_class_string = line.split(': ')[1]
        node_id_to_uid[target_class] = target_class_string[1:-2]

    # Loads the final mapping of integer node ID to human-readable string
    node_id_to_name = {}
    for key, val in node_id_to_uid.items():
      if val not in uid_to_human:
        tf.logging.fatal('Failed to locate: %s', val)
      name = uid_to_human[val]
      node_id_to_name[key] = name

    return node_id_to_name

  def id_to_string(self, node_id):
    if node_id not in self.node_lookup:
      return ''
    return self.node_lookup[node_id]


def create_graph():
  """Creates a graph from saved GraphDef file and returns a saver."""
  # Creates graph from saved graph_def.pb.
  with tf.gfile.FastGFile(os.path.join(
      FLAGS.model_dir, 'classify_image_graph_def.pb'), 'rb') as f:
    graph_def = tf.GraphDef()
    graph_def.ParseFromString(f.read())
    _ = tf.import_graph_def(graph_def, name='')


def run_inference_on_images(image_list, output_dir):
  """Runs inference on an image list.

  Args:
    image_list: a list of images.
    output_dir: the directory in which image vectors will be saved

  Returns:
    image_to_labels: a dictionary with image file keys and predicted
      text label values
  """
  image_to_labels = defaultdict(list)

  create_graph()

  with tf.Session() as sess:
    # Some useful tensors:
    # 'softmax:0': A tensor containing the normalized prediction across
    #   1000 labels.
    # 'pool_3:0': A tensor containing the next-to-last layer containing 2048
    #   float description of the image.
    # 'DecodeJpeg/contents:0': A tensor containing a string providing JPEG
    #   encoding of the image.
    # Runs the softmax tensor by feeding the image_data as input to the graph.
    softmax_tensor = sess.graph.get_tensor_by_name('softmax:0')

    for image_index, image in enumerate(image_list):
      try:
        print("parsing", image_index, image, "\n")
        if not tf.gfile.Exists(image):
          tf.logging.fatal('File does not exist %s', image)

        with tf.gfile.FastGFile(image, 'rb') as f:
          image_data =  f.read()

          predictions = sess.run(softmax_tensor,
                          {'DecodeJpeg/contents:0': image_data})

          predictions = np.squeeze(predictions)

          ###
          # Get penultimate layer weights
          ###

          feature_tensor = sess.graph.get_tensor_by_name('pool_3:0')
          feature_set = sess.run(feature_tensor,
                          {'DecodeJpeg/contents:0': image_data})
          feature_vector = np.squeeze(feature_set)        
          outfile_name = os.path.basename(image) + ".npz"
          out_path = os.path.join(output_dir, outfile_name)
          np.savetxt(out_path, feature_vector, delimiter=',')

          # Creates node ID --> English string lookup.
          node_lookup = NodeLookup()

          top_k = predictions.argsort()[-FLAGS.num_top_predictions:][::-1]
          for node_id in top_k:
            human_string = node_lookup.id_to_string(node_id)
            score = predictions[node_id]
            print("results for", image)
            print('%s (score = %.5f)' % (human_string, score))
            print("\n")

            image_to_labels[image].append(
              {
                "labels": human_string,
                "score": str(score)
              }
            )

        # close the open file handlers
        proc = psutil.Process()
        open_files = proc.open_files()

        for open_file in open_files:
          file_handler = getattr(open_file, "fd")
          os.close(file_handler)
      except:
        print('could not process image index',image_index,'image', image)

  return image_to_labels


def maybe_download_and_extract():
  """Download and extract model tar file."""
  dest_directory = FLAGS.model_dir
  if not os.path.exists(dest_directory):
    os.makedirs(dest_directory)
  filename = DATA_URL.split('/')[-1]
  filepath = os.path.join(dest_directory, filename)
  if not os.path.exists(filepath):
    def _progress(count, block_size, total_size):
      sys.stdout.write('\r>> Downloading %s %.1f%%' % (
          filename, float(count * block_size) / float(total_size) * 100.0))
      sys.stdout.flush()
    filepath, _ = urllib.request.urlretrieve(DATA_URL, filepath, _progress)
    print()
    statinfo = os.stat(filepath)
    print('Succesfully downloaded', filename, statinfo.st_size, 'bytes.')
  tarfile.open(filepath, 'r:gz').extractall(dest_directory)


def main(_):
  maybe_download_and_extract()
  if len(sys.argv) < 2:
    print("please provide a glob path to one or more images, e.g.")
    print("python classify_image_modified.py '../cats/*.jpg'")
    sys.exit()

  else:
    output_dir = "image_vectors"
    if not os.path.exists(output_dir):
      os.makedirs(output_dir)

    images = glob.glob(sys.argv[1])
    image_to_labels = run_inference_on_images(images, output_dir)

    with open("image_to_labels.json", "w") as img_to_labels_out:
      json.dump(image_to_labels, img_to_labels_out)

    print("all done")
if __name__ == '__main__':
  tf.app.run()

5

Ви можете використовувати Perceptual Image Diff

Це утиліта командного рядка, яка порівнює два зображення за допомогою перцептивної метрики. Тобто він використовує обчислювальну модель зорової системи людини, щоб визначити, чи візуально різні зображення відрізняються, тому незначні зміни в пікселях ігноруються. Крім того, це різко зменшує кількість помилкових спрацьовувань, спричинених різницею в генерації випадкових чисел, різницею в ОС чи машинної архітектури.


4

Це складна проблема! Це залежить від того, наскільки точним вам потрібно бути, і від того, з якими типами зображень ви працюєте. Ви можете використовувати гістограми для порівняння кольорів, але це, очевидно, не враховує просторовий розподіл цих кольорів у зображеннях (тобто фігури). Виявлення країв, яке супроводжується якоюсь сегментацією (тобто виділення фігур), може забезпечити шаблон для узгодження з іншим зображенням. Ви можете використовувати матриці coocurence для порівняння текстур, розглядаючи зображення як матриці значень пікселів, і порівнюючи ці матриці. Є кілька хороших книг про відповідність зображень та машинний зір - пошук на Amazon знайде деякі.

Сподіваюся, це допомагає!


3

Деякі програмні рішення для розпізнавання зображень насправді не ґрунтуються на чисто алгоритмах, а замість цього використовують концепцію нейронної мережі . Перегляньте http://en.wikipedia.org/wiki/Artificial_neural_network, а саме NeuronDotNet, який також включає цікаві зразки: http://neurondotnet.freehostia.com/index.html


1
посилання neurondotnet.freehostia.com мертве
Моніка Хеднек

3

Існує відповідне дослідження з використанням нейронних мереж Кохонена / самоорганізуючих карт

Існують як більш академічні системи (Google для PicSOM), так і менш академічні
( http://www.generation5.org/content/2004/aiSomPic.asp , (можливо, не підходять для всіх робочих середовищ)).


3

Обчислення суми квадратів різниць значень кольорів пікселів у різко зменшеному варіанті (наприклад: 6x6 пікселів) працює добре. Ідентичні зображення дають 0, схожі зображення дають малі цифри, різні зображення дають великі.

Ідея інших наведених вище хлопців спочатку звучить інтригуюче - хоча моя ідея чудово працює, я хочу, щоб мої зображення розраховувались як "різні", щоб це дало правильний результат - навіть з точки зору кольорового сліпого спостерігача.


2

Це звучить як проблема із зором. Можливо, ви захочете ознайомитися з адаптивним підсиленням, а також алгоритмом вилучення лінії Бернса. Концепції цих двох повинні допомогти підійти до вирішення цієї проблеми. Розпізнавання країв - ще простіше почати, якщо ви новачок в алгоритмах зору, оскільки це пояснює основи.

Що стосується параметрів для категоризації:

  • Палітра кольорів і розташування (розрахунок градієнта, гістограма кольорів)
  • Містяться фігури (Ада. Підсилення / навчання для виявлення фігур)

2

Залежно від того, наскільки точні результати вам потрібні, ви можете просто розбити зображення на блоки nxn пікселів та проаналізувати їх. Якщо ви отримуєте різні результати в першому блоці, ви не можете зупинити обробку, що призведе до деяких покращень продуктивності.

Наприклад, для аналізу квадратів можна отримати суму значень кольору.



1

Ви можете виконати якусь оцінку руху збігу між двома зображеннями та виміряти загальну суму залишків та витрат на вектор руху (подібно до того, як це було б зроблено у відеокодері). Це компенсувало б рух; для бонусних балів зробіть оцінку руху за афінним перетворенням (компенсує масштабування та розтягування тощо). Ви також можете робити блоки, що перекриваються, або оптичний потік.


1

Спочатку можна спробувати використовувати кольорові гістограми. Однак вам дійсно потрібно звузити проблемний домен. Загальне узгодження зображень є дуже складною проблемою.


1

Вибачення за приєднання до кінця дискусії.

Ми навіть можемо використовувати методологію ORB для виявлення подібних точок об’єктів між двома зображеннями. Наступне посилання дає пряму реалізацію ORB в python

http://scikit-image.org/docs/dev/auto_examples/plot_orb.html

Навіть openCV має пряму реалізацію ORB. Якщо вам потрібна додаткова інформація, дотримуйтесь статті дослідження, поданої нижче.

https://www.researchgate.net/publication/292157133_Image_Matching_Using_SIFT_SURF_BRIEF_and_ORB_Performance_Comparison_for_Distorted_Images


0

У іншій темі є кілька хороших відповідей на це питання, але мені цікаво, чи спрацює щось із спектральним аналізом? Тобто, розбийте зображення на інформацію про фазу та амплітуду та порівняйте їх. Це може уникнути деяких проблем із обрізанням, трансформацією та різницею інтенсивності. У будь-якому випадку, це лише я припускаю, оскільки це здається цікавою проблемою. Якщо ви шукали за адресою http://scholar.google.com, я впевнений, ви могли б запропонувати кілька статей щодо цього.


спектральний аналіз із перетворенням Фур'є, кольорової гістограми немає, оскільки ви можете реконструювати зображення з двох частин - уявної та реальної. (не знаю, чи буде це працювати, просто повідомляючи вас, що це не в цій категорії).
nlucaroni

Так, я мав на увазі перетворення Фур’є.
neuroguy123
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.