유사한 이미지를 찾기위한 알고리즘


83

두 이미지가 '유사한 지'여부를 판단하고 비슷한 패턴의 색상, 밝기, 모양 등을 인식 할 수있는 알고리즘이 필요합니다. 인간의 뇌가 이미지를 '분류'하기 위해 사용하는 매개 변수에 대한 포인터가 필요할 수 있습니다. ..

hausdorff 기반 매칭을 살펴 봤지만 주로 변형 된 물체와 모양의 패턴을 매칭하는 것 같습니다.


이 다른 유사한 질문에 좋은 답변이 있습니다. stackoverflow.com/questions/25977/…
blak

2
많은 '할 수있다'와 '마이트'. 누구나 이러한 모든 제안을 시도하고 무엇이 가장 좋은지 알고 있습니까?
john ktejik 2013 년

답변:


60

wavelet transform을 사용하여 이미지를 서명으로 분해하여 비슷한 작업을 수행했습니다 .

내 접근 방식은 변환 된 각 채널에서 가장 중요한 n 개의 계수 를 선택 하고 위치를 기록하는 것이 었습니다. 이것은 abs (power)에 따라 (power, location) 튜플 목록을 정렬하여 수행되었습니다. 유사한 이미지는 동일한 장소에서 중요한 계수를 갖는다는 점에서 유사성을 공유합니다.

이미지를 YUV 형식으로 변환하는 것이 가장 좋다는 것을 알았습니다. 이렇게하면 모양 (Y 채널)과 색상 (UV 채널)에서 가중치 유사성을 효과적으로 사용할 수 있습니다.

mactorii 에서 위의 구현을 찾을 수 있습니다. 안타깝게도 내가 가져야 할만큼 작업하지 않았습니다. :-)

제 친구들이 놀라 울 정도로 좋은 결과를내는 또 다른 방법은 단순히 이미지 크기를 줄여서 4x4 픽셀과 당신의 서명 인 저장소를 만드는 것입니다. 두 이미지 사이의 맨해튼 거리 를 해당 픽셀을 사용하여 계산하여 두 이미지가 얼마나 유사한 지 점수를 매길 수 있습니다 . 크기 조정을 수행 한 방법에 대한 세부 정보가 없으므로 해당 작업에 사용할 수있는 다양한 알고리즘을 사용하여 적합한 알고리즘을 찾아야 할 수 있습니다.


7
4x4 방법으로 크기를 조정하는 것은 멋진 아이디어이지만 (당신의 방법이 좋지 않다는 것은 아닙니다) 첫 번째 방법이 더 간단합니다.
Alix Axel

@freespace, 당신이 "해당 픽셀을 사용하여 두 이미지 사이의 맨해튼 거리를 계산"설명해주십시오 수
암 비카

1
@Ambika : 각 픽셀의 색상을 길이가 3 인 벡터로 취급하고 비교되는 이미지에서 해당 픽셀 사이의 맨해튼 거리를 계산합니다. 그것은 당신에게 4 맨해튼 거리를 제공합니다. 그로부터 단일 측정 값을 도출하는 방법은 귀하에게 달려 있습니다. 가장 분명한 것은 그것들을 합치는 것입니다.
freespace

45

pHash 가 관심을 가질 수 있습니다.

지각 해시 n. 포함 된 오디오 또는 시각적 콘텐츠를 수학적으로 기반으로하는 오디오, 비디오 또는 이미지 파일의 지문. 입력의 작은 변화로 인한 눈사태 효과에 의존하여 출력의 급격한 변화에 의존하는 암호화 해시 함수와 달리, 입력이 시각적으로 또는 청각 적으로 유사한 경우 지각 해시는 서로 "가까이"있습니다.


8
pHash의 웹 사이트를 확인했습니다. 현재 사이트에는 두 개의 이미지를 업로드 할 수있는이 기능이 있으며 유사 여부를 알려줍니다. 비슷한 이미지 10 개와 그렇지 않은 이미지 10 개를 시도했습니다. 불행히도 성공률은 그다지 인상적이지 않았습니다.
rodrigo-silveira

2
pHash는 실제로 매우 엄격합니다. 덜 엄격한 경향이있는 'ahash'또는 평균 해시를 사용할 수 있습니다. github.com/JohannesBuchner/imagehash/blob/master/…
Rohit

13

SIFT 를 사용 하여 다른 이미지에서 동일한 물체를 다시 감지했습니다. 정말 강력하지만 다소 복잡하고 과잉 일 수 있습니다. 이미지가 매우 유사해야한다면 두 이미지의 차이를 기반으로 한 몇 가지 간단한 매개 변수를 통해 꽤 많은 것을 알 수 있습니다. 몇 가지 지침 :

  • 이미지를 정규화합니다. 즉, 두 이미지의 평균 밝기를 계산하고 비율에 따라 가장 밝게 조정하여 두 이미지의 평균 밝기를 동일하게 만듭니다 (최고 수준에서 클리핑을 방지하기 위해). 색깔.
  • 채널당 정규화 된 이미지에 대한 색상 차이의 합계입니다.
  • 이미지에서 가장자리를 찾고 두 이미지에서 가장자리 픽셀 사이의 거리를 측정합니다. (모양 용)
  • 이미지를 일련의 불연속 영역으로 나누고 각 영역의 평균 색상을 비교합니다.
  • 하나 (또는 ​​세트) 수준에서 이미지를 임계 값으로 설정하고 결과 흑백 이미지가 다른 픽셀 수를 계산합니다.

이미지 유사성을 계산하기 위해 선별과 유사한 기능을 사용하는 코드를 가리킬 수 있습니까?
mrgloom

죄송합니다. 공개적으로 사용 가능한 코드는 있지만 제가 아는 코드는 없습니다. 이 사이트에는 몇 가지 예가 있습니다. 예를 들면 다음과 같습니다. stackoverflow.com/questions/5461148/…
jilles de wit

.Net 용 어코드 프레임 워크 ( accord-framework.net )에는 다양한 커널 및 클러스터링 알고리즘을 사용하여 SURF, BagOfVisualWords, Harris Corner Detection 등을 수행하기위한 몇 가지 훌륭한 클래스가 있습니다.
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를 사용할 수 있습니다.

지각 메트릭을 사용하여 두 이미지를 비교하는 명령 줄 유틸리티입니다. 즉, 인간 시각 시스템의 계산 모델을 사용하여 두 이미지가 시각적으로 다른지 확인하므로 픽셀의 사소한 변경은 무시됩니다. 또한 난수 생성, OS 또는 시스템 아키텍처 차이의 차이로 인해 발생하는 오 탐지 수를 대폭 줄입니다.


4

어려운 문제입니다! 얼마나 정확해야하는지에 따라 다르며 작업중인 이미지의 종류에 따라 다릅니다. 히스토그램을 사용하여 색상을 비교할 수 있지만 이미지 내에서 해당 색상의 공간적 분포 (즉, 모양)를 고려하지 않은 것은 분명합니다. 가장자리 감지에 이어 어떤 종류의 분할 (즉, 모양 선택)이 다른 이미지와 일치하는 패턴을 제공 할 수 있습니다. coocurence 행렬을 사용하여 이미지를 픽셀 값의 행렬로 간주하고 해당 행렬을 비교하여 텍스처를 비교할 수 있습니다. 이미지 매칭과 머신 비전에 대한 좋은 책이 있습니다. Amazon에서 검색하면 일부를 찾을 수 있습니다.

도움이 되었기를 바랍니다!



3

코호 넨 신경망 / 자체 구성지도를 사용한 관련 연구가 있습니다.

더 많은 학술 시스템 (Google for PicSOM) 또는 덜 학술적
( http://www.generation5.org/content/2004/aiSomPic.asp , (모든 작업 환경에 적합하지 않을 수 있음)) 프레젠테이션이 모두 존재합니다.


3

대폭 축소 된 버전 (예 : 6x6 픽셀)의 픽셀 색상 값 차이 제곱의 합을 계산하는 것은 잘 작동합니다. 동일한 이미지는 0, 유사한 이미지는 작은 수를, 다른 이미지는 큰 이미지를 생성합니다.

위의 다른 사람들이 먼저 YUV에 침입하려는 아이디어는 흥미로워 들립니다. 내 아이디어는 훌륭하게 작동하지만 색맹 관찰자의 관점에서도 올바른 결과를 얻을 수 있도록 내 이미지가 "다른"것으로 계산되기를 바랍니다.


2

이것은 시력 문제처럼 들립니다. Burns Line Extraction 알고리즘뿐만 아니라 Adaptive Boosting을 살펴볼 수도 있습니다. 이 두 가지 개념은이 문제에 접근하는 데 도움이 될 것입니다. 엣지 감지는 기본 사항을 설명하므로 비전 알고리즘을 처음 접하는 경우 시작하기에 훨씬 더 간단한 곳입니다.

범주화를위한 매개 변수 :

  • 색상 팔레트 및 위치 (그라데이션 계산, 색상 히스토그램)
  • 포함 된 도형 (Ada. 부스팅 / 형상 감지 훈련)

2

얼마나 정확한 결과가 필요한지에 따라 이미지를 nxn 픽셀 블록으로 나누고 분석 할 수 있습니다. 첫 번째 블록에서 다른 결과를 얻는 경우 처리를 중지 할 수 없으므로 성능이 약간 향상됩니다.

사각형을 분석하기 위해 예를 들어 색상 값의 합계를 얻을 수 있습니다.



1

두 이미지 사이에 일종의 블록 매칭 모션 추정을 수행하고 잔차와 모션 벡터 비용의 전체 합계를 측정 할 수 있습니다 (비디오 인코더에서 수행하는 것과 유사). 이것은 움직임을 보상합니다. 보너스 포인트의 경우 아핀 변환 동작 추정을 수행합니다 (확대 및 늘이기 등을 보상합니다). 중첩 된 블록이나 광학 흐름을 수행 할 수도 있습니다.


1

첫 번째 단계로 컬러 히스토그램을 사용해 볼 수 있습니다. 그러나 문제 영역을 좁혀 야합니다. 일반적인 이미지 매칭은 매우 어려운 문제입니다.


1

토론 후반에 참여해 주셔서 죄송합니다.

ORB 방법론을 사용하여 두 이미지 사이의 유사한 특징점을 감지 할 수도 있습니다. 다음 링크는 파이썬에서 ORB를 직접 구현합니다.

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.