개발

[퍼즐:01] 퍼즐 조각 외곽선 추출

hellojkw 2023. 8. 6. 18:10

https://hellojkw.tistory.com/entry/직소-퍼즐-맞추는-프로그램-단계

 

직소 퍼즐 맞추는 프로그램 단계

퍼즐에 번호 쓰기 퍼즐 스캔 여러 퍼즐 이미지에서 각각의 이미지로 절단 퍼즐 조각에 써있는 번호 인식 퍼즐 조각에서 Outline 추출 Outline에서 Edge 추출 Edge Normalize Hole, Head 쌍 만들기 Piece에서 그

hellojkw.tistory.com

퍼즐을 맞추기 위한 단계 중 핵심은 사진을 디지털 퍼즐 객체로 바꾸는 것이다.

그 첫 번재가 외곽선을 추출하는 것.

 

Canny 라는 알고리즘이 대표적인 윤곽선 알고리즘인데 잘 모르겠어서 접어뒀다.

 

배경과 전경(사물)을 분리하는 알고리즘으로 GrabCut을 알게 되었다.

속도가 너무 느리기도 하고 퍼즐에 잘 맞지도 않았다.

알고리즘이 퍼즐을 사물로 인식을 잘 못하는 것 같다.

배경이 흰색, 검정색 모두 잘 동작하지 않았고,

그림자 문제 해결도 쉽지 않았다.

 

그리고 처음엔 LINQPad에서 C#으로 개발했었는데,

모든 예제가 python으로 되어 있어서 

어차피 맥북 많이 쓰니까 테스트는 그냥 맥에서 python으로 했다.

 

다시 돌고돌아 Canny로 왔다.

Canny를 쓰기 전처리를 해야겠다는 생각을 했다.

 

1. 흰/검 으로 구분

2. 노이즈 제거

 

두가지가 중요했는데,

가우시안 필터로 노이즈를 제거하고,

흰/검으로 변경했더니 잘 동작했다.

 

순서

  1. 회색조로 변경
  2. 가우시안 필터 적용
  3. 흰/검 으로 변환
  4. Canny 적용

 

윤곽선을 추출했다!

 

이제 코너를 찾고, 엣지를 추출해야 한다.

 

코드의 각종 값은 대충 동작하는 선에서 대충 넣은 것.. (공부를 많이 하진 않음..ㅋㅋ)

https://github.com/jkwchunjae/JigsawPuzzleSolver/commit/f00f261e6d08e1372d8bd5db70779fdd2d3d49bc

import cv2

# 이미지를 불러오고 그레이스케일로 변환
image = cv2.imread('20230804_225655_3.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gaussian = cv2.GaussianBlur(gray, (5, 5), 0)
_, black_white = cv2.threshold(gaussian, 127, 255, cv2.THRESH_BINARY)

# 경계선 검출 (Canny edge detection 예제)
edges = cv2.Canny(black_white, 50, 255)

cv2.imshow('gray', gray);
cv2.imshow('gaussian', gaussian);
cv2.imshow('black_white', black_white);

# 경계선 검출 결과에서 퍼즐 조각의 외곽을 감싸는 경계 상자를 찾음
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
puzzle_contour = max(contours, key=cv2.contourArea)
cv2.drawContours(image, [puzzle_contour], -1, (0, 255, 0), 2);

# 퍼즐 영역 추출
# x, y, w, h = cv2.boundingRect(puzzle_contour)
# puzzle_area = image[y:y+h, x:x+w]

# 결과 이미지 출력
cv2.imshow('Puzzle Area', image)
cv2.waitKey(0)
cv2.destroyAllWindows()