iT邦幫忙

1

python 圖像比較一問

  • 分享至 

  • xImage

各位好

公司有一個項目, 想把資料夾內的全部圖像作比較然後給5個最相似的圖像名稱找出來.

資料夾1= source
資料夾2= target

source 的資料夾放了大約500張圖片
然後, 我需要輸入一張圖片來找尋尋source 的全部圖片的相似度%(這個相似度需要在python 以% 顯示出來)

然後把圖片copy 到target 資料夾中.
我在網上找了幾遍, 但是只找到2張圖片的比對

這個有點難,望指教

hokou iT邦好手 1 級 ‧ 2024-02-01 09:36:51 檢舉
用 for 迴圈全部跑一輪,再挑出最高的 N 張?
sam0407 iT邦大師 1 級 ‧ 2024-02-02 11:04:18 檢舉
Output需求很明確(相似度以%表示),但缺少最重要的決策邏輯,似定度的判斷邏輯是什麼?每個人看的角度不同會有很大的爭議喔~~
cyris iT邦新手 5 級 ‧ 2024-02-02 14:40:45 檢舉
就是一幅圖的全部跟資料夾內的圖作比較
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

1
貓虎皮
iT邦新手 3 級 ‧ 2024-02-04 22:55:32

因為不清楚您想要的比較標準究竟為何,所以我從三個較簡單的面向進行切入,分別是:

  1. 顏色比較
  2. 圖片特徵
  3. 易混淆程度

代碼如下:

(您可以透過更改COMPARE_BASED_ON來設定比較的標準,更改SELECTED_IMAGE_NAME來設定選擇的檔案)

'''
2024 (c) MaoHuPi
imageComp/main.py
'''

SOURCE_DIR = 'image/source'
TARGET_DIR = 'image/target'
SELECTED_IMAGE_NAME = 'image (6).jpg'
COMPARE_BASED_ON = 'cnn_confusion_degree' # can be 'pixel_hsv_difference_sum', 'cnn_image_features', or 'cnn_confusion_degree'

import os
from pathlib import Path
import shutil

sourceDir = os.path.abspath(SOURCE_DIR)
if not os.path.exists(sourceDir): raise Exception(f'Can not found SOURCE_DIR({sourceDir})')
targetDir = os.path.abspath(TARGET_DIR)
if not os.path.exists(targetDir): os.makedirs(targetDir)
selectedImage = os.path.join(sourceDir, SELECTED_IMAGE_NAME)
compareImages = [os.path.join(sourceDir, name) for name in os.listdir(sourceDir) if name != SELECTED_IMAGE_NAME]

if COMPARE_BASED_ON == 'pixel_hsv_difference_sum':
	# 逐一比較各像素顏色之hsv並在乘上權重後加總、排序
	HSV_W = [1, 0.2, 0.2] # hsv 各通道權重

	import cv2
	import numpy as np

	def prepareImage(url):
		image = cv2.imread(url)
		image = cv2.resize(image, (256, 256), interpolation=cv2.INTER_AREA)
		image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
		return image
	
	differenceList = []
	selectedImage = prepareImage(selectedImage)
	for compareImage in compareImages:
		compareImage = prepareImage(compareImage)
		differenceList.append(np.sum(np.abs(selectedImage - compareImage)[:,:]*np.array(HSV_W), axis=None, dtype=float)) # 因為色相對於畫面整體的影響通常大於明、暗程度,所以在此乘上權重值
	
	differenceMin = 0 # 因為選擇的圖片與其自身之差異為 0 且相似度為 100%
	differenceMax = np.max(differenceList)
	differenceList = np.array(differenceList)
	differenceList = 1 - (differenceList - differenceMin)/(differenceMax - differenceMin)
	rank = sorted([[i, differenceList[i]] for i in range(len(differenceList))], key=lambda ISPair: ISPair[1], reverse=True)

elif COMPARE_BASED_ON == 'cnn_image_features':
	# 根據cnn所找出的特徵之差異性來進行排序
	import cv2
	import numpy as np 
	from tensorflow.keras.backend import eval as TFKEval
	from tensorflow.keras.models import Sequential
	from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
	from tensorflow.keras.utils import to_categorical 
	from tensorflow.keras.callbacks import Callback
	from PIL import Image
	import matplotlib.pyplot as plt

	model = Sequential()
	model.add(Conv2D(32, kernel_size = 3, input_shape = (256, 256, 3), padding = "same", activation = 'relu', name='conv2d_1'))
	model.add(MaxPooling2D(pool_size = 2))
	model.add(Flatten())
	model.add(Dense(200, activation = 'relu'))
	model.add(Dense(200, activation = 'relu'))
	model.add(Dense(200, activation = 'relu'))
	model.add(Dense(200, activation = 'relu'))
	model.add(Dense(1+len(compareImages), activation = 'softmax'))
	model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
	
	class CustomCallback(Callback):
		def on_test_batch_end(self, batch, logs=None):
			if logs.get('accuracy') >= 0.95:
				self.model.stop_training = True
				print('\nval_accuracy >= 0.95\n')

	def prepareImage(url):
		image = cv2.imread(url)
		image = cv2.resize(image, (256, 256), interpolation=cv2.INTER_AREA)
		image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
		return image
	xTrain = np.array([prepareImage(compareImage) for compareImage in [selectedImage, *compareImages]])
	xTrain = xTrain/255
	yTrain = np.array(list(range(1+len(compareImages))))
	yTrain = to_categorical(yTrain)

	model.fit(xTrain, yTrain,
		batch_size=64,
		epochs=50,
		verbose=1,
		validation_data=(xTrain, yTrain),
		callbacks=[CustomCallback()])
	
	selectedImageFeature = None
	compareImagesFeature = []
	conv2d_1 = model.get_layer('conv2d_1')
	for i in range(len(xTrain)):
		feature = conv2d_1(np.array([xTrain[i]]))
		if i == 0: selectedImageFeature = feature
		else: compareImagesFeature.append(feature)
	
	differenceList = []
	selectedImageFeature = selectedImageFeature.numpy()
	for compareImageFeature in compareImagesFeature:
		compareImageFeature = compareImageFeature.numpy()
		differenceList.append(np.sum(np.abs(selectedImageFeature - compareImageFeature), axis=None, dtype=float))
	differenceMin = 0 # 因為選擇的圖片與其自身之差異為 0 且相似度為 100%
	differenceMax = np.max(differenceList)
	differenceList = np.array(differenceList)
	differenceList = 1 - (differenceList - differenceMin)/(differenceMax - differenceMin)
	rank = sorted([[i, differenceList[i]] for i in range(len(differenceList))], key=lambda ISPair: ISPair[1], reverse=True)
	
elif COMPARE_BASED_ON == 'cnn_confusion_degree':
	# 根據「對於未完全擬和之cnn來說的易混淆程度」來進行排序
	import cv2
	import numpy as np 
	from tensorflow.keras.backend import eval as TFKEval
	from tensorflow.keras.models import Sequential
	from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
	from tensorflow.keras.utils import to_categorical 
	from tensorflow.keras.callbacks import Callback
	from PIL import Image
	import matplotlib.pyplot as plt

	model = Sequential()
	model.add(Conv2D(32, kernel_size = 3, input_shape = (256, 256, 3), padding = "same", activation = 'relu', name='conv2d_1'))
	model.add(MaxPooling2D(pool_size = 2))
	model.add(Flatten())
	model.add(Dense(200, activation = 'relu'))
	model.add(Dense(200, activation = 'relu'))
	model.add(Dense(200, activation = 'relu'))
	model.add(Dense(200, activation = 'relu'))
	model.add(Dense(1+len(compareImages), activation = 'softmax'))
	model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
	
	class CustomCallback(Callback):
		def on_test_batch_end(self, batch, logs=None):
			if logs.get('accuracy') >= 0.7:
				self.model.stop_training = True
				print('\nval_accuracy >= 0.95\n')

	def prepareImage(url):
		image = cv2.imread(url)
		image = cv2.resize(image, (256, 256), interpolation=cv2.INTER_AREA)
		image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
		return image
	xTrain = np.array([prepareImage(compareImage) for compareImage in [selectedImage, *compareImages]])
	xTrain = xTrain/255
	yTrain = np.array(list(range(1+len(compareImages))))
	yTrain = to_categorical(yTrain)

	model.fit(xTrain, yTrain,
		batch_size=64,
		epochs=50,
		verbose=1,
		validation_data=(xTrain, yTrain),
		callbacks=[CustomCallback()])
	
	selectedImageFeature = None
	compareImagesFeature = []
	for i in range(len(xTrain)):
		output = model.predict(np.array([xTrain[i]]))
		if i == 0: selectedImageFeature = output
		else: compareImagesFeature.append(output)
	
	differenceList = []
	selectedImageFeature = selectedImageFeature
	for compareImageFeature in compareImagesFeature:
		compareImageFeature = compareImageFeature
		differenceList.append(np.sum(np.abs(selectedImageFeature - compareImageFeature), axis=None, dtype=float))
	differenceMin = 0 # 因為選擇的圖片與其自身之差異為 0 且相似度為 100%
	differenceMax = np.max(differenceList)
	differenceList = np.array(differenceList)
	differenceList = 1 - (differenceList - differenceMin)/(differenceMax - differenceMin)
	rank = sorted([[i, differenceList[i]] for i in range(len(differenceList))], key=lambda ISPair: ISPair[1], reverse=True)

print(*['{similarity}% :\n{path}'.format(path=compareImages[ISPair[0]], similarity=str(int(ISPair[1]*100)).rjust(3, ' ')) for ISPair in rank[:5]], sep='\n')
for i in [ISPair[0] for ISPair in rank[:5]]:
	shutil.copyfile(compareImages[i], os.path.join(targetDir, os.path.basename(compareImages[i])))

希望有幫助到您=^w^=

貓虎皮 iT邦新手 3 級 ‧ 2024-02-05 18:25:37 檢舉

我將三種模式統整,並做成了工具,專案連結:
https://github.com/MaoHuPi/imageComp

0
fagolino
iT邦見習生 ‧ 2024-02-24 11:12:13

This sample program is only a basic framework and you may need to make further adjustments and optimizations according to your Buckshot Roulette specific needs. For example, you can implement a more complex similarity calculation method, or add an error handling mechanism to handle situations where the image cannot be found or cannot be read.

我要發表回答

立即登入回答