diff --git a/back-end/error.txt b/back-end/error.txt deleted file mode 100644 index 884eba9d84aafcbc3a98f09d0d32b86e81fb4977..0000000000000000000000000000000000000000 --- a/back-end/error.txt +++ /dev/null @@ -1,26 +0,0 @@ -Traceback (most recent call last): - File "/home/sang/automated_image_processing/automated_image_processing/automated_image_processing/back-end/oop/test.py", line 10, in <module> - objects = clothesDetector.localize_objects(image) - File "/home/sang/automated_image_processing/automated_image_processing/automated_image_processing/back-end/oop/temp.py", line 302, in localize_objects - objects = client.object_localization( - File "/home/sang/.conda/envs/autoImage/lib/python3.10/site-packages/google/cloud/vision_helpers/decorators.py", line 112, in inner - response = self.annotate_image( - File "/home/sang/.conda/envs/autoImage/lib/python3.10/site-packages/google/cloud/vision_helpers/__init__.py", line 76, in annotate_image - r = self.batch_annotate_images( - File "/home/sang/.conda/envs/autoImage/lib/python3.10/site-packages/google/cloud/vision_v1/services/image_annotator/client.py", line 567, in batch_annotate_images - response = rpc( - File "/home/sang/.conda/envs/autoImage/lib/python3.10/site-packages/google/api_core/gapic_v1/method.py", line 113, in __call__ - return wrapped_func(*args, **kwargs) - File "/home/sang/.conda/envs/autoImage/lib/python3.10/site-packages/google/api_core/grpc_helpers.py", line 74, in error_remapped_callable - raise exceptions.from_grpc_error(exc) from exc -google.api_core.exceptions.Unauthenticated: 401 Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project. [reason: "ACCESS_TOKEN_EXPIRED" -domain: "googleapis.com" -metadata { - key: "service" - value: "vision.googleapis.com" -} -metadata { - key: "method" - value: "google.cloud.vision.v1.ImageAnnotator.BatchAnnotateImages" -} -] \ No newline at end of file diff --git a/back-end/googleAPI.md b/back-end/googleAPI.md index 0e9e20b5cee03cae8a241affdcabd0c3d656f67e..44a4a78bfc1bde8a252c5fbde419884d5e48a42a 100644 --- a/back-end/googleAPI.md +++ b/back-end/googleAPI.md @@ -1,4 +1,5 @@ 구글 Cloud Vision API의 설정법을 다룹니다. +```bash sudo apt-get install apt-transport-https ca-certificates gnupg echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt @@ -14,9 +15,12 @@ gcloud init export GOOGLE_APPLICATION_CREDENTIALS="KEY_PATH" export GOOGLE_APPLICATION_CREDENTIALS="/home/sang/automated_image_processing/automated_image_processing/automated_image_processing/back-end/google_cloud_vision_key.json" +``` google.api_core.exceptions.Unauthenticated: 401 Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project. [reason: "ACCESS_TOKEN_EXPIRED"... -> 시간 에러입니다. 작동중인 서버의 시간을 확인해주세요. WSL환경에서 자주 발생합니다. 재부팅이 답입니다. sudo chown -R mongodb:mongodb /var/lib/mongodb -sudo chown mongodb:mongodb /tmp/mongodb-27017.sock \ No newline at end of file +sudo chown mongodb:mongodb /tmp/mongodb-27017.sock + +export GOOGLE_APPLICATION_CREDENTIALS="C:\SDP\automated_image_processing\back-end\source_code\google_cloud_vision_key.json" \ No newline at end of file diff --git "a/back-end/source_code/image_data/ssfshop/beanpole/\353\202\250\353\205\200\352\263\265\354\232\251 \353\262\240\354\235\264\354\247\201 \355\224\274\354\274\200 \355\213\260\354\205\224\354\270\240 - \353\270\224\353\236\231/DallE.png" "b/back-end/source_code/image_data/ssfshop/beanpole/\353\202\250\353\205\200\352\263\265\354\232\251 \353\262\240\354\235\264\354\247\201 \355\224\274\354\274\200 \355\213\260\354\205\224\354\270\240 - \353\270\224\353\236\231/DallE.png" new file mode 100644 index 0000000000000000000000000000000000000000..2d5449288bea3e8a25760515af48c43241c15f4e Binary files /dev/null and "b/back-end/source_code/image_data/ssfshop/beanpole/\353\202\250\353\205\200\352\263\265\354\232\251 \353\262\240\354\235\264\354\247\201 \355\224\274\354\274\200 \355\213\260\354\205\224\354\270\240 - \353\270\224\353\236\231/DallE.png" differ diff --git "a/back-end/source_code/image_data/ssfshop/beanpole/\353\202\250\353\205\200\352\263\265\354\232\251 \353\262\240\354\235\264\354\247\201 \355\224\274\354\274\200 \355\213\260\354\205\224\354\270\240 - \353\270\224\353\236\231/original.jpg" "b/back-end/source_code/image_data/ssfshop/beanpole/\353\202\250\353\205\200\352\263\265\354\232\251 \353\262\240\354\235\264\354\247\201 \355\224\274\354\274\200 \355\213\260\354\205\224\354\270\240 - \353\270\224\353\236\231/original.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..e02410b14d9f31887f9ca3fcc70376e8e08ad230 Binary files /dev/null and "b/back-end/source_code/image_data/ssfshop/beanpole/\353\202\250\353\205\200\352\263\265\354\232\251 \353\262\240\354\235\264\354\247\201 \355\224\274\354\274\200 \355\213\260\354\205\224\354\270\240 - \353\270\224\353\236\231/original.jpg" differ diff --git a/back-end/source_code/main.py b/back-end/source_code/main.py index f5d185c121db7a231a9b79bf42d2a8f77e72754b..1ffa5e3e932988068e9bde9fe9ce172e7393ca92 100644 --- a/back-end/source_code/main.py +++ b/back-end/source_code/main.py @@ -1,20 +1,24 @@ import json +import sys from modules import image_processor +from modules import fileManager +from modules import object_detector from modules import database -with open("download.json", 'r') as file: + +with open(sys.argv[1], 'r', encoding='UTF8') as file: shoppingmall_data = json.load(file) seller_brand_path = shoppingmall_data["seller"]+"/"+shoppingmall_data["brand"] -imageDownloder = image_processor.ImageDownloader() +imageDownloder = fileManager.ImageDownloader() imageFactory = image_processor.ImageFactory() imageProcessor = image_processor.ImageProcessor() -faceDetector = image_processor.FaceDetector() -clothesDetector = image_processor.ClothesDetector() +faceDetector = object_detector.FaceDetector() +clothesDetector = object_detector.ClothesDetector() databaseManager = database.DatabaseManager() @@ -33,5 +37,6 @@ for product in shoppingmall_data["product_list"]: clothes = clothesDataList.getClothes(product["type_of_clothes"]) clothes.denormalizeByImageSize(image) - databaseManager.insertToClothesDataCollection(image, image_url, result_image, face, clothes) + + databaseManager.insertToClothesDataCollection(image, image_url, result_image, face, clothes) \ No newline at end of file diff --git a/back-end/source_code/modules/__pycache__/database.cpython-39.pyc b/back-end/source_code/modules/__pycache__/database.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d04a323e9ab29e71af0c500ec12f0d3e0abb572 Binary files /dev/null and b/back-end/source_code/modules/__pycache__/database.cpython-39.pyc differ diff --git a/back-end/source_code/modules/__pycache__/fileManager.cpython-39.pyc b/back-end/source_code/modules/__pycache__/fileManager.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a897909e1da7e7acd106e5187d52fca3da809621 Binary files /dev/null and b/back-end/source_code/modules/__pycache__/fileManager.cpython-39.pyc differ diff --git a/back-end/source_code/modules/__pycache__/image_processor.cpython-39.pyc b/back-end/source_code/modules/__pycache__/image_processor.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8d3dec6760e223c73cfadc243d06f5a694b22909 Binary files /dev/null and b/back-end/source_code/modules/__pycache__/image_processor.cpython-39.pyc differ diff --git a/back-end/source_code/modules/__pycache__/object_detector.cpython-39.pyc b/back-end/source_code/modules/__pycache__/object_detector.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..79476f37b0afd090d88e8a3991691285eb79bb52 Binary files /dev/null and b/back-end/source_code/modules/__pycache__/object_detector.cpython-39.pyc differ diff --git a/back-end/source_code/modules/__pycache__/system.cpython-39.pyc b/back-end/source_code/modules/__pycache__/system.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7de2f5d7cf62b235d7a33022b0e713fda857a821 Binary files /dev/null and b/back-end/source_code/modules/__pycache__/system.cpython-39.pyc differ diff --git a/back-end/source_code/modules/background.py b/back-end/source_code/modules/background.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/back-end/source_code/modules/fileManager.py b/back-end/source_code/modules/fileManager.py index bfbde175324be0a58073bc989489dee41f05f247..2a656bf311ccfd01d845e51d1cb692d1915ee1fc 100644 --- a/back-end/source_code/modules/fileManager.py +++ b/back-end/source_code/modules/fileManager.py @@ -1,4 +1,5 @@ import requests +import os class ImageDownloader: def download_image(self, url, folder_path, file_name): response = requests.get(url) @@ -7,4 +8,5 @@ class ImageDownloader: image_path = folder_path+"/"+file_name with open(image_path, 'wb') as file: file.write(response.content) - return image_path + return os.path.normpath(os.path.abspath(image_path)) + diff --git a/back-end/source_code/modules/image_processor.py b/back-end/source_code/modules/image_processor.py index 9c02e77ae9e4a0571e3bb8930fe4f61c1fe5b0a0..29cd56b250ed96308d583c20faf3f5ba3c879444 100644 --- a/back-end/source_code/modules/image_processor.py +++ b/back-end/source_code/modules/image_processor.py @@ -4,15 +4,42 @@ import onnxruntime import os import subprocess -from modules import fileManager +from modules import fileManager, system + + +class ImageSaver: + def saveImage(self, file_path, image, name = None): + if name is None: + name = "unlabeled.jpg" + if os.path.isdir(file_path): # 입력 경로가 파일이 아니라 디렉터리일 경우, + file_path = os.path.dirname(file_path) + save_path = os.path.join(file_path, name) + else: + file_path = os.path.dirname(file_path) + save_path = os.path.join(file_path, name) + else: + if '.' not in name: + name = name + ".jpg" + if os.path.isdir(file_path): # 입력 경로가 파일이 아니라 디렉터리일 경우, + file_path = os.path.dirname(file_path) + save_path = os.path.join(file_path, name) + else: + file_path = os.path.dirname(file_path) + save_path = os.path.join(file_path, name) + print(save_path) + cv2.imwrite(save_path, image.cv_image) + + class Image: def __init__(self, filepath, cv_image): - self.filepath = filepath + if filepath is not None: + self.filepath = os.path.abspath(filepath) if cv_image is not None: self.cv_image = cv_image else: - self.cv_image = cv2.imread(filepath) + img_array = np.fromfile(filepath, np.uint8) + self.cv_image = cv2.imdecode(img_array, cv2.IMREAD_COLOR) self.height = self.cv_image.shape[0] self.width = self.cv_image.shape[1] self.url = None @@ -92,8 +119,8 @@ class PaddedImageFactory: class DallEImage(PaddedImage): def __init__(self, filepath, cv_image, offset, ratio): super().__init__(filepath, cv_image, offset, ratio) -class DallEImageGenerator: - def createDallEImage(self, imageDownloader, padded_image, image_path): +class Outpainter: + def outpaintUsingDallE(self, imageDownloader, padded_image, image_path): if not isinstance(padded_image, PaddedImage): raise ValueError("Invalid input. Only objects of class PaddedImage are allowed.") @@ -115,9 +142,8 @@ class DallEImageGenerator: folder_path = os.path.dirname(image_path) dallE_image_path = imageDownloader.download_image(image_url, folder_path, "DallE.png" ) - dallE_CV_image = cv2.imread(dallE_image_path) - dallE_obj = DallEImage(dallE_image_path, dallE_CV_image, (padded_image.x_offset,padded_image.y_offset), padded_image.ratio) + dallE_obj = DallEImage(dallE_image_path, None, (padded_image.x_offset,padded_image.y_offset), padded_image.ratio) return dallE_obj @@ -195,21 +221,11 @@ class AlphaCompositer: magick_command = "magick" subprocess.run([magick_command,"composite", "-geometry", "+" + str(x_offset) + "+" +str(y_offset), "temp_fearthered.png", "temp_alpha.png", "temp_alpha.png"]) - cv_image_composition = cv2.imread("temp_alpha.png") - AlphaComposited_obj = PaddedImage("temp_alpha.png", cv_image_composition, (x_offset, y_offset), dallE_image.ratio) + AlphaComposited_obj = PaddedImage("temp_alpha.png", None, (x_offset, y_offset), dallE_image.ratio) return AlphaComposited_obj -class SystemChecker: - def __init__(self): - import platform - self.system = platform.system() - def returnMagickCommand(self): - if self.system == 'Linux': - magick_command = "./magick.appimage" - elif self.system == 'Windows': - magick_command = "magick" - return magick_command + class ImageChopper: @@ -218,7 +234,8 @@ class ImageChopper: object_move_x = paddedImage.x_offset object_move_y = paddedImage.y_offset - magick_command = SystemChecker().returnMagickCommand() + + magick_command = system.SystemChecker().returnMagickCommand() if mask.smallest_box_x == 0: subprocess.run([magick_command,"convert", "temp_alpha.png", "-gravity", "west", "-chop", (str(paddedImage.x_offset)+"x"+"0"), "temp_alpha.png"]) @@ -231,12 +248,13 @@ class ImageChopper: if mask.smallest_box_y + mask.smallest_box_height + 10 >= mask.height: print(magick_command,"convert", "temp_alpha.png", "-gravity", "south", "-chop", ("0"+"x"+str(paddedImage.y_offset)), "temp_alpha.png") subprocess.run([magick_command,"convert", "temp_alpha.png", "-gravity", "south", "-chop", ("0"+"x"+str(paddedImage.y_offset)), "temp_alpha.png"]) - - folder_path = os.path.dirname(image_path) + ''' + folder_path = os.path.abspath(image_path) file_path = folder_path + "/result.png" + os.remove(file_path) os.rename("temp_alpha.png", file_path) - result_cv_image = cv2.imread(file_path) - result = PaddedImage(file_path, result_cv_image, (object_move_x, object_move_y), None) + ''' + result = PaddedImage("temp_alpha.png", None, (object_move_x, object_move_y), None) return result @@ -245,7 +263,7 @@ class ImageProcessor: def __init__(self): self.maskGenerator = MaskGenerator() self.paddedImageFactory = PaddedImageFactory() - self.dallEImageGenerator= DallEImageGenerator() + self.outpainter= Outpainter() self.featheredImageFactory = FeatheredImageFactory() self.alphaCompositer = AlphaCompositer() self.imageChopper = ImageChopper() @@ -253,8 +271,9 @@ class ImageProcessor: def process(self, image): mask = self.maskGenerator.create_mask(image) padded_image = self.paddedImageFactory.create_padded_image(image, mask, 55) - dallE_image = self.dallEImageGenerator.createDallEImage(self.imageDownloder, padded_image, image.filepath) + dallE_image = self.outpainter.outpaintUsingDallE(self.imageDownloder, padded_image, image.filepath) feathered_image = self.featheredImageFactory.applyFeather(image) resized_outpainted_image = self.alphaCompositer.alphaCompositingWithResizing(feathered_image, dallE_image) result_image = self.imageChopper.chopInvadingBorderUsingMask(resized_outpainted_image, mask, image.filepath) + ImageSaver().saveImage(image.filepath, result_image, "result") return result_image diff --git a/back-end/source_code/modules/object_detector.py b/back-end/source_code/modules/object_detector.py index d8471fa5b42e2635889bace3e8e3ce9f142af0e4..4863b70bf6dec6ab2a7253e72e9bda9a55836a23 100644 --- a/back-end/source_code/modules/object_detector.py +++ b/back-end/source_code/modules/object_detector.py @@ -17,9 +17,10 @@ class FaceDataList: return Face(face_location[0], face_location[1], face_location[2], face_location[3]) class FaceDetector: - def detectFace(self,image): + # https://github.com/serengil/retinaface + def detectFace(self, image): from retinaface import RetinaFace - faceDataList = FaceDataList(RetinaFace.detect_faces(image.filepath)) + faceDataList = FaceDataList(RetinaFace.detect_faces(image.cv_image)) return faceDataList class BoxDrower: def drawBox(self, image, left_top, right_bottom): diff --git a/back-end/source_code/modules/system.py b/back-end/source_code/modules/system.py new file mode 100644 index 0000000000000000000000000000000000000000..0c90e04a98d9631c798d25d3bd0505a2f142a54a --- /dev/null +++ b/back-end/source_code/modules/system.py @@ -0,0 +1,14 @@ +class SystemChecker: + def __init__(self): + import platform + self.system = platform.system() + def returnMagickCommand(self): + if self.system == 'Linux': + magick_command = "./magick.appimage" + elif self.system == 'Windows': + magick_command = "magick" + return magick_command +''' +class FileDirectory: + def __init__(self, file_path): +''' diff --git a/back-end/source_code/requirements.txt b/back-end/source_code/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc812623f33881ec4b38095456d17c5a072fa9a0 --- /dev/null +++ b/back-end/source_code/requirements.txt @@ -0,0 +1,8 @@ +numpy +onnxruntime +opencv-python +retina-face +google-cloud-vision +pymongo +openai +python-dotenv \ No newline at end of file diff --git a/back-end/source_code/test.py b/back-end/source_code/test.py deleted file mode 100644 index 129bc28bc4c9a5af307ba919e0027f5ac50ad6eb..0000000000000000000000000000000000000000 --- a/back-end/source_code/test.py +++ /dev/null @@ -1,4 +0,0 @@ -from modules import database - -databaseManager = database.DatabaseManager() -