[퍼즐:01] 퍼즐 조각 외곽선 추출
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. 노이즈 제거
두가지가 중요했는데,
가우시안 필터로 노이즈를 제거하고,
흰/검으로 변경했더니 잘 동작했다.
순서
- 회색조로 변경
- 가우시안 필터 적용
- 흰/검 으로 변환
- 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()