edit: api 변경 - 벡터이미지검색 -> 결과물에 parts 추가, 파츠검색 api 추가
This commit is contained in:
@@ -18,11 +18,28 @@ ViTL14_336 = "clip-vit-large-patch14-336"
|
||||
|
||||
#download/save path
|
||||
PRETRAINED_MODEL_PATH = "./datas"
|
||||
FAISS_VECTOR_PATH = "./datas"
|
||||
VECTOR_IMG_LIST_PATH = "./datas"
|
||||
FAISS_VECTOR_PATH = "./datas/Eyewear_001~500_ComponentsCapture_20251121"
|
||||
VECTOR_IMG_LIST_PATH = "./datas/Eyewear_001~500_ComponentsCapture_20251121"
|
||||
|
||||
INDEX_IMAGES_PATH = "./datas/eyewear_all"
|
||||
|
||||
class VectorSearchItem:
|
||||
glass = "glass"
|
||||
bridge = "Bridge"
|
||||
hinge = "Hinges"
|
||||
lens = "Lens"
|
||||
nosepad = "Nose pad"
|
||||
other = "other"
|
||||
padarm = "Padarm"
|
||||
rim = "Rim"
|
||||
rivet = "Rivet"
|
||||
soltex = "Soltex"
|
||||
temple = "Temple"
|
||||
templetip = "Temple tip"
|
||||
|
||||
class ImageDepths:
|
||||
parts = "Parts"
|
||||
thumnails = "Thumbnails"
|
||||
|
||||
# report image consts
|
||||
class ReportInfoConst:
|
||||
|
||||
@@ -100,21 +100,37 @@ def save_report_image(report_info, report_image_path):
|
||||
table_setting(report_info, report_image_path)
|
||||
|
||||
|
||||
def get_clip_info(model, query_image_path, top_k=4):
|
||||
def get_clip_info(model, query_image_path, item_info, top_k=4):
|
||||
"""
|
||||
이미지 유사도 검색
|
||||
"""
|
||||
index_file_path = os.path.join(VECTOR_IMG_LIST_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}_{DEFAULT_INDEX_NAME_SUFFIX}')
|
||||
txt_file_path = os.path.join(VECTOR_IMG_LIST_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}.txt')
|
||||
index_file_path = os.path.join(VECTOR_IMG_LIST_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}_{item_info}_{DEFAULT_INDEX_NAME_SUFFIX}')
|
||||
txt_file_path = os.path.join(VECTOR_IMG_LIST_PATH,f'{model.name}_{os.path.basename(model.value[1].trained_model)}_{model.value[1].index_type}_{item_info}.txt')
|
||||
vector_model = VectorSimilarity(model_info=model,
|
||||
index_file_path=index_file_path,
|
||||
txt_file_path=txt_file_path)
|
||||
|
||||
image_lists = []
|
||||
if not os.path.exists(txt_file_path):
|
||||
if item_info == VectorSearchItem.glass:
|
||||
image_lists = find_glass_folder_images(VECTOR_IMG_LIST_PATH)
|
||||
else:
|
||||
image_lists = find_parts_folder_images(VECTOR_IMG_LIST_PATH, item_info)
|
||||
|
||||
if image_lists:
|
||||
with open(txt_file_path, 'w') as f:
|
||||
for img_path in image_lists:
|
||||
f.write(f"{img_path}\n")
|
||||
else:
|
||||
with open(txt_file_path, 'r') as f:
|
||||
image_lists = [line.strip() for line in f.readlines()]
|
||||
|
||||
# vector_model.create_feature_extraction_model(FEMUsageInfo.openaiclipvit)
|
||||
|
||||
vector_model.save_index_from_files(images_path=INDEX_IMAGES_PATH,
|
||||
vector_model.save_index_from_files(images_path_lists=image_lists,
|
||||
save_index_dir=FAISS_VECTOR_PATH,
|
||||
save_txt_dir=VECTOR_IMG_LIST_PATH,
|
||||
item_info=item_info,
|
||||
index_type=model.value[1].index_type)
|
||||
|
||||
inference_times, result_img_paths, result_percents = vector_model.query_faiss(query_image_path, top_k=top_k)
|
||||
@@ -131,5 +147,56 @@ def get_clip_info(model, query_image_path, top_k=4):
|
||||
)
|
||||
|
||||
return report_info
|
||||
|
||||
def find_glass_folder_images(root_folder):
|
||||
"""
|
||||
glass(thumnails) 폴더 내의 모든 이미지 파일 경로를 재귀적으로 탐색하여 리스트로 반환합니다.
|
||||
|
||||
Args:
|
||||
root_folder (str): 탐색을 시작할 최상위 폴더
|
||||
|
||||
Returns:
|
||||
list: 발견된 이미지 파일 전체 경로의 리스트.
|
||||
"""
|
||||
image_paths = []
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(root_folder):
|
||||
|
||||
if os.path.basename(dirpath) == ImageDepths.thumnails:
|
||||
|
||||
for filename in filenames:
|
||||
if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
|
||||
|
||||
# 파일의 전체 경로를 생성하여 리스트에 추가
|
||||
full_path = os.path.join(dirpath, filename)
|
||||
image_paths.append(full_path)
|
||||
|
||||
return image_paths
|
||||
|
||||
|
||||
def find_parts_folder_images(root_folder, parts):
|
||||
"""
|
||||
parts 폴더 내의 해당하는 파츠 이미지 파일 경로를 재귀적으로 탐색하여 리스트로 반환합니다.
|
||||
|
||||
Args:
|
||||
root_folder (str): 탐색을 시작할 최상위 폴더
|
||||
|
||||
Returns:
|
||||
list: 발견된 이미지 파일 경로의 리스트.
|
||||
"""
|
||||
image_paths = []
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(root_folder):
|
||||
|
||||
if os.path.basename(dirpath) == ImageDepths.parts:
|
||||
|
||||
for filename in filenames:
|
||||
if filename.lower().endswith(('.png', '.jpg', '.jpeg')) and parts in filename:
|
||||
|
||||
# 파일의 전체 경로를 생성하여 리스트에 추가
|
||||
full_path = os.path.join(dirpath, filename)
|
||||
image_paths.append(full_path)
|
||||
|
||||
return image_paths
|
||||
|
||||
|
||||
|
||||
@@ -234,73 +234,67 @@ class VectorSimilarity:
|
||||
feature_vectors = self.fem_model.image_embedding(image_data_np)
|
||||
return feature_vectors
|
||||
|
||||
def save_index_from_files(self, images_path=None, save_index_dir=None, save_txt_dir=None, index_type=INDEX_TYPE_L2):
|
||||
def save_index_from_files(self, images_path_lists=None, save_index_dir=None, save_txt_dir=None, item_info=None, index_type=INDEX_TYPE_L2):
|
||||
"""
|
||||
인덱스 정보 저장
|
||||
:param images_path: 이미지 파일 경로
|
||||
:param save_index_dir: 인덱스 저장 디렉토리
|
||||
:param save_txt_dir: 이미지 경로 저장 디렉토리
|
||||
:param item_info: 아이템 정보
|
||||
:param index_type: 인덱스 타입 (L2, Cosine)
|
||||
:return: 이미지 임베딩 차원 정보
|
||||
"""
|
||||
assert self.fem_model is not None, 'invalid fem_model'
|
||||
assert images_path is not None, 'images_path is required'
|
||||
assert images_path_lists is not None, 'images_path is required'
|
||||
|
||||
if not os.path.exists(images_path):
|
||||
log.error(f'image_path={images_path} does not exist')
|
||||
|
||||
image_folder = images_path
|
||||
result = None
|
||||
|
||||
# 모든 이미지 임베딩 모으기
|
||||
if os.path.exists(image_folder):
|
||||
image_paths = [os.path.join(image_folder, image_file) for image_file in os.listdir(image_folder)]
|
||||
image_vectors = np.vstack([self.image_embedding_from_file(image_file) for image_file in image_paths])
|
||||
log.debug(f'image_vectors.shape={image_vectors.shape}')
|
||||
result = image_vectors.shape
|
||||
image_paths = images_path_lists
|
||||
image_vectors = np.vstack([self.image_embedding_from_file(image_file) for image_file in image_paths])
|
||||
log.debug(f'image_vectors.shape={image_vectors.shape}')
|
||||
result = image_vectors.shape
|
||||
|
||||
# 인덱스 생성 (L2)
|
||||
dimension = image_vectors.shape[1]
|
||||
# 인덱스 생성 (L2)
|
||||
dimension = image_vectors.shape[1]
|
||||
|
||||
if index_type == INDEX_TYPE_L2:
|
||||
index = faiss.IndexFlatL2(dimension) # L2
|
||||
elif index_type == INDEX_TYPE_COSINE:
|
||||
index = faiss.IndexFlatIP(dimension) # cosine
|
||||
faiss.normalize_L2(image_vectors)
|
||||
else:
|
||||
raise Exception(f'Invalid index_type={index_type}')
|
||||
|
||||
index.add(image_vectors)
|
||||
|
||||
# 인덱스 저장
|
||||
if save_index_dir is None:
|
||||
save_index_path = os.path.join(FILE_BASE_PATH,f'{self.fem_model_name}_{os.path.basename(self.fem_model_args.trained_model)}_{index_type}_{DEFAULT_SAVE_INDEX_SUFFIX}')
|
||||
self.index_file_path = save_index_path
|
||||
else:
|
||||
save_index_path = os.path.join(save_index_dir,f'{self.fem_model_name}_{os.path.basename(self.fem_model_args.trained_model)}_{index_type}_{DEFAULT_SAVE_INDEX_SUFFIX}')
|
||||
os.makedirs(save_index_dir, exist_ok=True)
|
||||
|
||||
# 이미지 경로 파일 저장
|
||||
if save_txt_dir is None:
|
||||
save_txt_path = os.path.join(FILE_BASE_PATH, f'{self.fem_model_name}_{os.path.basename(self.fem_model_args.trained_model)}_{index_type}.txt')
|
||||
self.txt_file_path = save_txt_path
|
||||
else:
|
||||
save_txt_path = os.path.join(save_txt_dir, f'{self.fem_model_name}_{os.path.basename(self.fem_model_args.trained_model)}_{index_type}.txt')
|
||||
os.makedirs(save_txt_dir, exist_ok=True)
|
||||
|
||||
if not os.path.exists(save_txt_path):
|
||||
faiss.write_index(index, save_index_path)
|
||||
log.debug(f'save_index_path={save_index_path}')
|
||||
|
||||
if not os.path.exists(save_txt_path):
|
||||
# 이미지 경로 저장
|
||||
with open(save_txt_path, 'w') as f:
|
||||
for path in image_paths:
|
||||
f.write(f"{path}\n")
|
||||
log.debug(f'save_txt_path={save_txt_path}')
|
||||
|
||||
if index_type == INDEX_TYPE_L2:
|
||||
index = faiss.IndexFlatL2(dimension) # L2
|
||||
elif index_type == INDEX_TYPE_COSINE:
|
||||
index = faiss.IndexFlatIP(dimension) # cosine
|
||||
faiss.normalize_L2(image_vectors)
|
||||
else:
|
||||
log.error(f'Image folder {image_folder} does not exist')
|
||||
raise Exception(f'Invalid index_type={index_type}')
|
||||
|
||||
index.add(image_vectors)
|
||||
|
||||
# 인덱스 저장
|
||||
if save_index_dir is None:
|
||||
save_index_path = os.path.join(FILE_BASE_PATH,f'{self.fem_model_name}_{os.path.basename(self.fem_model_args.trained_model)}_{index_type}_{item_info}_{DEFAULT_SAVE_INDEX_SUFFIX}')
|
||||
self.index_file_path = save_index_path
|
||||
else:
|
||||
save_index_path = os.path.join(save_index_dir,f'{self.fem_model_name}_{os.path.basename(self.fem_model_args.trained_model)}_{index_type}_{item_info}_{DEFAULT_SAVE_INDEX_SUFFIX}')
|
||||
os.makedirs(save_index_dir, exist_ok=True)
|
||||
|
||||
# # 이미지 경로 파일 저장
|
||||
# if save_txt_dir is None:
|
||||
# save_txt_path = os.path.join(FILE_BASE_PATH, f'{self.fem_model_name}_{os.path.basename(self.fem_model_args.trained_model)}_{index_type}.txt')
|
||||
# self.txt_file_path = save_txt_path
|
||||
# else:
|
||||
# save_txt_path = os.path.join(save_txt_dir, f'{self.fem_model_name}_{os.path.basename(self.fem_model_args.trained_model)}_{index_type}.txt')
|
||||
# os.makedirs(save_txt_dir, exist_ok=True)
|
||||
|
||||
if not os.path.exists(save_index_path):
|
||||
faiss.write_index(index, save_index_path)
|
||||
log.debug(f'save_index_path={save_index_path}')
|
||||
|
||||
# if not os.path.exists(save_txt_path):
|
||||
# # 이미지 경로 저장
|
||||
# with open(save_txt_path, 'w') as f:
|
||||
# for path in image_paths:
|
||||
# f.write(f"{path}\n")
|
||||
# log.debug(f'save_txt_path={save_txt_path}')
|
||||
|
||||
|
||||
return result
|
||||
|
||||
def set_index_path(self, index_path):
|
||||
@@ -394,7 +388,7 @@ def test():
|
||||
|
||||
# cm.create_feature_extraction_model(FEMUsageInfo.openaiclipvit)
|
||||
|
||||
cm.save_index_from_files(images_path=INDEX_IMAGES_PATH,
|
||||
cm.save_index_from_files(images_path_lists=INDEX_IMAGES_PATH,
|
||||
save_index_dir=FAISS_VECTOR_PATH,
|
||||
save_txt_dir=VECTOR_IMG_LIST_PATH,
|
||||
index_type=model.value[1].index_type)
|
||||
|
||||
31
custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/utils.py
Normal file
31
custom_apps/FEATURE_VECTOR_SIMILARITY_FAISS/utils.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from custom_apps.FEATURE_VECTOR_SIMILARITY_FAISS.const import *
|
||||
|
||||
def search_glass_parts(image_path_list):
|
||||
result = []
|
||||
|
||||
for image_path in image_path_list:
|
||||
parts_path = Path(os.path.join(os.path.dirname(os.path.dirname(image_path)),ImageDepths.parts))
|
||||
parts_files_generator = parts_path.rglob('*.png')
|
||||
|
||||
parts_list = []
|
||||
# parts_list = [str(p.resolve()) for p in parts_files_generator] # 풀경로
|
||||
|
||||
for p in parts_files_generator:
|
||||
# name,ext = os.path.splitext(p.name)
|
||||
parts_list.append(p.name)
|
||||
result.append(parts_list)
|
||||
|
||||
return result
|
||||
|
||||
def file_name_to_parts(file_path):
|
||||
filename, ext = os.path.splitext(os.path.basename(file_path))
|
||||
|
||||
name_list = filename.split('_')
|
||||
|
||||
result = name_list[2:][0]
|
||||
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user