各位好
公司有一個項目, 想把資料夾內的全部圖像作比較然後給5個最相似的圖像名稱找出來.
資料夾1= source
資料夾2= target
source 的資料夾放了大約500張圖片
然後, 我需要輸入一張圖片來找尋尋source 的全部圖片的相似度%(這個相似度需要在python 以% 顯示出來)
然後把圖片copy 到target 資料夾中.
我在網上找了幾遍, 但是只找到2張圖片的比對
這個有點難,望指教
因為不清楚您想要的比較標準究竟為何,所以我從三個較簡單的面向進行切入,分別是:
代碼如下:
(您可以透過更改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^=
我將三種模式統整,並做成了工具,專案連結:
https://github.com/MaoHuPi/imageComp
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.