[AIFFEL] 22.Jan.11 - Exploration, Object-detection

Deok Jong Moon·2022년 1월 11일
0

학습한 개념

  • cv2.imshow()는 커널이 죽는다.
    : https://stackoverflow.com/questions/43943333/cv2-imshow-crashes-kernel
    : 찾아보니 로컬에서 실행해서 이미지를 보이려면 뭔가 또 해야한단다.

  • OpenCV의 cv2.imread()는 이미지 색을 RGB가 아닌 BGR로 가져옴
    : 이거 순서 cv2.cvtColor()로 바꿔줘야 편함
    : 혹은 B,G,R을 cv2.split()으로 분리 및 할당 후 cv2.merge()로 합쳐서 다시 할당해도 됨

  • obeject detection과 스티커 붙이기의 큰 그림

    • bounding box 추출
    • face landmark localization(bounding box를 이용함)
    • landmark의 인덱스를 알아내서, 알고 싶은 부분의 인덱스를 활용해 좌표를 구한다
    • 거기로부터 이미지를 붙일 좌표를 다시 구한다
      • 좌표는 bounding box 대비 비율로 해야 다른 사진을 읽어와도 쓸 수 있다.
      • 왜냐하면 사진마다 얼굴 크기(즉 카메라로부터의 거리 등)가 다를 것이니
      • 즉, 스티커를 갖다붙일 때 절대값스럽게(예: x 픽셀 위) 하면 안 됨.
    • 좌표 및 합성할 이미지 사이즈를 통해 그 부분만 슬라이싱 해오고
    • np.where()조건식을 통해 갖다 붙일 부분만 붙이고, 나머지는 원본을 참조하게끔 한다.
  • HOG 알고리즘 face detector

  • 이미지 피라미드

  • landmark 모델

  • zip() 은 인자값끼리 개수가 달라도 되나보다

t1 = [1,2,3]
t2 = ['a', 'b', 'c', 'd']

for num, let in zip(t1, t2):
    print(num, let)

>>>
1 a
2 b
3 c
  • OpenCV()는 crop 기능이 없단다.
    : 그래서 그냥 ndarray 슬라이싱 기능으로 가져오기...

미니프로젝트

오늘의 목표 : 사진 속 얼굴을 찾고, 얼굴의 랜드마크를 이용해 적절한 위치에 콧수염 이미지를 합성한다.

  • 이미지는 우리 첫째 아들 이미지를 썼다.
  • 콧수염 이미지는 아이펠에서 제공받은 이미지이다.
    • png 파일이고 콧수염 부분만 검정색, 나머지는 흰 바탕이다.
    • 사이즈가 정방형이어서 콧수염 크기만큼 나중에 slicing으로 crop했다.
  • object keypoint estimation(landmark 찾기)은 Dlib에서 제공하는 ibug 300-W 데이터셋을 pre-trained한 모델을 사용했다.(모델은 wget을 통해 다운로드 받았다)
  • 그리고 문제 없이 이미지들을 로드하고, 예상한 곳에 콧수염 이미지를 넣어봤는데...

헤맨 점

  • dlib.get_frontal_face_detector(img file, 이미지 피라미드 upsamping 수)

    • 여기서 upsampling 수를 늘려봤다. 1일 때는 좀 넓었고, 2일 때는 bounding box가 작아졌다.(얼굴이 살짝 기울어져 있었는데 밑의 턱라인이 살짝 잘렸다.)
      : 다 담는 쪽으로 해야지 나중에 return으로 나온 좌표값을 잘 활용할 수 있지 않을까 싶다.
  • cv2.addWeighted(img1, w1, img2, w2, b) 함수 써서 블렌딩하기

    1. 블렌딩 방법론 정하기
      1) 스티커 사진을 원본 이미지로 늘리기
      • 보니까 사진 2개의 사이즈가 같아야 한다.
      • 스티커 사진을 키우고, 여백을 백색으로 넣어볼까?
      • 근데 다른 방법이 있단다.(그래서 실행 X)
      2) 스티커 사진 사이즈에 맞게 원본 잘라오기
      • 그리고 두 개를 blending 후 다시 원본에 덮어씌우려 했다(slicing으로)
      • 근데 블렌딩이 잘 안된다.
      • 내가 원한 건 cv2.addWeighted(img1, w1, img2, w2, b)에서 w11로 해서 원본은 전혀 변화가 없고, w2img2 투명해지기 위해 0.7 정도로 되는 것인데,
      • 그러니 사진이 새하얘진다.(gamma=b가 없었음)
      3) gamma 값으로 새하얀 거 빼보기(-255 대입)
      • 살짝 감이 잡혀 -255에 영향을 안 받도록 img1의 가중치를 2로 해보자'라는 식으로
        cv2.addWeighted(img1, 2, img2, 0.5, -255)를 했더니
      • 좀 괜찮다.
      • 근데 살짝 보니 원본 사진의 색감이 달라졌다.(*2배 한 게 아닌 것 같다.)
      4) img1 미리 영향 갈 수만큼 더해보자
      • 결국 수식이라는 감이 잡혔다.
      • cv2.addWeighted(img1 + (255/10*6), 1, img2, 0.6, -(255/10*6))로 했는데
      • 아예 오류가 나버린다.(Bad arguments 란다.)
      • 찾아보니 이미지 값은 0~255만 가질 수 있다고 하는데, 아마 저런 수식이 어떤 곳에서 음수 혹은 255 이상의 양수가 나와서 그런 것 같다.
      5) 일단 마무리
      • 시간이 다 되어 일단 마무리를 하기 위해 다른 사람들이 한 아래의 코드로 했다
      • cv2.addWeighted(img1, 0.5, img2, 0.5, 0)
      • 이 후에 이 부분을 원본 이미지에 slicing으로 덮어씌웠는데(np.where(스티커이미지==255, 원본 슬라이싱 부분, 스티커이미지)) 사용
      • 사실 이 부분도 slicing된 부분의 원본 이미지 투명도가 낮아지기 때문에 궁극적으로 내가 원한 코드는 아닌 것 같다.
      6) 이후에 고민해본 것들
      • 찾아 보니 음수, 255 이상의 양수가 되는 값들은 다른 곳에 저장되게 할 수 있단다.
      • 그렇게 저장하고 나중에 빼주거나 더해주면 어떨까...?
      • 근데 이것도 결국 cv2 함수 내부에서는 해주는 게 불가능할 것 같다.(예를 들어 img2 의 하얀 배경을 지워주기 위해 일정 값을 (-)해야 하는데, 이러면 img2 내부의 작은 수가 있는 픽셀은 어쩔 수 없이 음수로 되어버린다. 그러면 다시 또 오류가 날 것이다)
      • 그래서 차라리 이럴바엔 그냥 cv2 함수 밖에서 numpy array로 값을 자체적으로 계산하는 게 더 낫겠다 싶었다...

더 공부할 것

  • object detection 기술...
  • HOG(Histogram of Oriented Gradients)의 원리
  • SVM의 원리
  • feature descriptor의 개념...
  • 이거 좀 중요한 것 같다...
profile
'어떻게든 자야겠어'라는 저 아이를 닮고 싶습니다

0개의 댓글