Python

opencv 과제1

jennyiscoding 2024. 5. 28. 13:41

Final!!

import cv2
import argparse
import os
import numpy as np
import uuid
import glob

from errors import CropVariableMiss, IsNotNumber, MainFileNotFoundError, MergeFileNotFoundError, OnlyPlusNumber, ResizeNumberEmpty, StartPointSmallThanFinalPoint


def isNumberCheck(number):
  try:
    if isinstance(float(number), (float, int)):
      return True
    else:
      return False
  except ValueError:
    return False
  
def isNumberAndPositiveCheck(number):
  try:
    if isinstance(float(number), (float, int)) and float(number) >= 0:
      return True
    else:
      return False
  except ValueError:
    return False
  
def makeSameChanngeImg():
    print('sameChannel')

def makeSameSizeImg(obImg, leftWidth, leftHeight):
    resizedImg = cv2.resize(obImg, (leftWidth, leftHeight))
    return resizedImg

def showAndCloseWd(img):
    cv2.namedWindow('image', cv2.WINDOW_AUTOSIZE)
    cv2.imshow('image', img)
    cv2.waitKey(0)  # 사용자가 아무 키나 누를 때까지 대기
    cv2.destroyAllWindows()
    return ''


def vstack(img, rightImage):
    # 위, 아래로 stack
    rImg = cv2.imread(rightImage, cv2.IMREAD_COLOR)
    leftHeight, leftWidth = img.shape[0:2]
    rImg_resized = makeSameSizeImg(rImg, leftWidth, leftHeight)
    vertical = np.vstack((img, rImg_resized))
    showAndCloseWd(vertical)
    return vertical


def blend(img, blendedImg):
    bImg = cv2.imread(blendedImg, cv2.IMREAD_COLOR)
    underHeight, underWidth = img.shape[0:2]
    bImg_resized = makeSameSizeImg(bImg, underWidth, underHeight)
    finalImg = cv2.addWeighted(img, 0.3, bImg_resized, 0.7, 0)
    showAndCloseWd(finalImg)
    return finalImg


def hstack(img, lowerImage):
  # 양옆으로 stack
  rImg = cv2.imread(lowerImage, cv2.IMREAD_COLOR)
  leftHeight, leftWidth = img.shape[0:2]
  rImg_resized = makeSameSizeImg(rImg, leftWidth, leftHeight)
  vertical = np.hstack((img, rImg_resized))
  showAndCloseWd(vertical)
  return vertical


def merge(img, upperImage):
  uimg = cv2.imread(upperImage, cv2.IMREAD_COLOR)
  if len(img.shape) == 2:  # 흑백 이미지인 경우
    img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    rows, cols = img.shape[0:2]
  
  rows, cols = img.shape[:2]

  upRows, upCols = uimg.shape[0:2]
  vpos = (cols - upCols) // 2  # 수평 위치
  hpos = (rows - upRows) // 2  # 수직 위치

  merged_img = img.copy()
  merged_img[hpos:hpos+upRows, vpos:vpos+upCols] = uimg
  showAndCloseWd(merged_img)
  return merged_img


def rotate(img, degree):
  rows, cols = img.shape[0:2]
  degree = float(degree)
  center_x = cols // 2
  center_y = rows // 2
  rotation_matrix = cv2.getRotationMatrix2D((center_x, center_y), degree, 1)
  rotated_img = cv2.warpAffine(img, rotation_matrix, (cols, rows))
  showAndCloseWd(rotated_img)
  return rotated_img


def crop(img, x0, y0, x1, y1):
  y=y0
  x=x0
  crop_img = img[y:y1, x:x1]
  showAndCloseWd(crop_img)
  return crop_img


def grayscale(img):
  processed_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  showAndCloseWd(processed_img)
  return processed_img


def resize(img, multipleInt):
  resize_img = cv2.resize(img, dsize=(0,0), fx=float(multipleInt), fy=float(multipleInt), interpolation=cv2.INTER_LINEAR)
  showAndCloseWd(resize_img)
  return resize_img


def handleError(e):
  if isinstance(e, MainFileNotFoundError):
    print(e)
  elif isinstance(e, CropVariableMiss):
    print(e)
  elif isinstance(e, MergeFileNotFoundError):
    print(e)
  elif isinstance(e, ResizeNumberEmpty):
    print(e)
  elif isinstance(e, IsNotNumber):
    print(e)
  elif isinstance(e, StartPointSmallThanFinalPoint):
    print(e)
  elif isinstance(e, OnlyPlusNumber):
    print(e)
  else:
    print(f"알 수 없는 오류가 발생했습니다: {e}, {type(e)}")
      

def img_process(imgFile, modeArr):
    try:
      img = cv2.imread(imgFile, cv2.IMREAD_COLOR)

      if img is None:
        raise MainFileNotFoundError(f"이미지를 찾을 수 없음: {imgFile}")

      for mode in modeArr:
        if('grayscale' in mode):
          img = grayscale(img)

        if('crop' in mode):
          args = mode.split('crop=')[1]
          x0, y0, x1,y1 = args.split('_')
          if not all([x0, y0, x1, y1]):
            raise CropVariableMiss("크롭 변수 중 한 개 이상의 값이 없습니다.")
          imgHeight, imgWidth = img.shape[0:2]

          if (isNumberAndPositiveCheck(x0) == False or isNumberAndPositiveCheck(x1) == False or isNumberAndPositiveCheck(y0) == False or isNumberAndPositiveCheck(y1) == False):
            print(isNumberAndPositiveCheck(0))
            raise IsNotNumber("crop 포인트는 0또는 양의 숫자가 들어가야 합니다")
          
          if (int(x0) > int(x1) or int(y0) > int(y1)):
            raise StartPointSmallThanFinalPoint(f"시작포인트는 끝나는 {imgWidth}, {imgHeight}포인트보다 작아야함")
          
          if (int(x0) > imgWidth or int(x1) > imgWidth or int(y0) > imgHeight or int(y1) > imgHeight):
            print(f'자르는 포인트가 이미지 크기를 벗어났습니다 range: {imgWidth}, {imgHeight}안에 들어가야 합니다')
            x0 = input("x0를 입력하세요")
            y0 = input("y0를 입력하세요")
            x1 = input("x1를 입력하세요")
            y1 = input("y1를 입력하세요")

          img = crop(img, int(x0), int(y0), int(x1), int(y1))
          # 문자넣으면 에러 나겠금

        if('rotate' in mode):
          degree = mode.split('=')[1]
          img = rotate(img, degree)
          if isNumberCheck(degree) == False:
            raise IsNotNumber("degree는 숫자가 들어가야 합니다")
          # 문자 예외처리 필요

        if('merge' in mode):
          mergeFile = mode.split('=')[1]
          if not os.path.isfile(mergeFile):
            raise MergeFileNotFoundError("merge할 파일이 존재하지 않습니다")
          img = merge(img, mergeFile)

        if('vstack' in mode):
          vstackFile = mode.split('=')[1]
          if not os.path.isfile(vstackFile):
            raise MergeFileNotFoundError("vstack할 파일이 존재하지 않습니다")
          img = vstack(img, vstackFile)
            
        if('hstack' in mode):
          hstackFile = mode.split('=')[1]
          if not os.path.isfile(hstackFile):
            raise MergeFileNotFoundError("hstack할 파일이 존재하지 않습니다")
          img = hstack(img, hstackFile)

        if('blend' in mode):
          underFile = mode.split('=')[1]
          if not os.path.isfile(underFile):
            raise MergeFileNotFoundError("blend할 파일이 존재하지 않습니다")
          img = blend(img, underFile)

        if('resize' in mode):
          size = mode.split('=')[1]
          if size == '':
            raise ResizeNumberEmpty("resize배수가 없습니다")
          
          if isNumberAndPositiveCheck(size) == False:
            raise IsNotNumber("resize 배율은 양의 숫자가 들어가야 합니다")
          img = resize(img, size)

    except Exception as e:
      handleError(e)
      return None
    
    return img


def save_img(image, resultDir):
  if not os.path.exists(resultDir):
    os.makedirs(resultDir)
  generated_uuid = uuid.uuid4()
  save_path = os.path.join(resultDir, f"{str(generated_uuid)}_suji.png")
  cv2.imwrite(save_path, image)


def extract_image_files(directory):
  image_extensions = ['*.jpg', '*.jpeg', '*.png', '*.bmp', '*.gif']

  image_files = []
  for extension in image_extensions:
      files = glob.glob(os.path.join(directory, extension))
      image_files.extend(files)

  return image_files

def main():
  parser = argparse.ArgumentParser(description='Process some images.')
  parser.add_argument('--img-dir', type=str, help='Directory containing images')
  parser.add_argument('--mode', type=str, help='Mode of processing')
  parser.add_argument('--result-dir', type=str, help='Directory to save results')
  args = parser.parse_args()

  if not (args.img_dir and args.mode and args.result_dir):
    print("Please provide all arguments: --img-dir, --mode, --result-dir")
    return
  
  imgFile = args.img_dir
  modeArr = args.mode.split(',')
  resultDir = args.result_dir

  allImageArr = extract_image_files(imgFile)

  for imageEach in allImageArr:
    resultImage = img_process(imageEach, modeArr)

    if resultImage is not None:
      save_img(resultImage, resultDir)
      cv2.destroyAllWindows()


if __name__ == "__main__":
  main()

# python homework2_final.py --img-dir=./ --result-dir=./result --mode=grayscale,crop=300_300_1000_680,resize=3,rotate=-45,merge=./reddot.png,vstack=./logo.png,hstack=./logo.png,blend=./logo.png