본문 바로가기
Python

opencv 과제1

by jennyiscoding 2024. 5. 28.

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