- cv2.HoughLinesP 및 object contour boxing 활용하여 직선만 추출
- 방법 1. 추출된 직선을 기준으로 이미지를 회전하여 변형
- 회전된 이미지에 직선을 시각화(변화 비교용)
- 방법 2. 직선 추출 불가시 object contour boxing 기법 사용
- 방법 1. 추출된 직선을 기준으로 이미지를 회전하여 변형
image noise에 따라 직선이나 object contour이 잘 안되는 경우 있음
- 히스토그램 평준화나 clahe 적용 후 rotation 진행하는 방법 고안중
(4/18 04:00 추가)
Y님의 피드백 통해 전처리 코드의 한계 확인
- image roation 각도가 너무 크게 돌아가는게 몇개 보이며 이미지 손실이 커짐
최소 회전을 위한 angle을 산출해 적게 회전하면서 이미지 내 픽셀보존 유지하려고 노력
import cv2
import numpy as np
import matplotlib.pyplot as plt
import glob
import random
# 이미지 파일 경로 리스트 가져오기
image_paths = glob.glob(r'C:\Users\kimdo\바탕 화면\AI Lab\cv-competition\data\test\*.jpg')
# 무작위로 9개의 이미지 선택
random_images = random.sample(image_paths, 9)
# 이미지 출력
fig, axes = plt.subplots(3, 3, figsize=(10, 10))
for i, image_path in enumerate(random_images):
image_ar = np.fromfile(image_path, np.uint8)
image = cv2.imdecode(image_ar, cv2.IMREAD_UNCHANGED)
# 회전을 위한 코드
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
# angle 초기화
angle = 0
reverse_angle = 0
final_angle = 0
try:
lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=200, minLineLength=120, maxLineGap=10)
angle = np.arctan2(lines[0][0][3] - lines[0][0][1], lines[0][0][2] - lines[0][0][0]) * 180 / np.pi
rows, cols = image.shape[:2]
#반대 방향 각도 계산
reverse_angle = 90 - abs(angle)
if abs(angle) <= reverse_angle:
if angle <= reverse_angle:
final_angle = angle
status = 'a.a <= r | a <= r'
else:
final_angle = angle
status = 'a.a <= r | a >= r'
# abs(angle) > reverse_angle:
else:
if angle <= reverse_angle:
final_angle = reverse_angle
status = 'a.a > r | a <= r'
else:
final_angle = -(reverse_angle)
status = 'a.a > r | a >= r'
if int(abs(reverse_angle)) == 45:
raise Exception('mod 2')
if reverse_angle != 0:
rotation_matrix = cv2.getRotationMatrix2D((cols / 2, rows / 2), final_angle, 1)
rotated_image = cv2.warpAffine(image, rotation_matrix, (cols, rows), borderMode=cv2.BORDER_CONSTANT, borderValue=(255, 255, 255))
# 시각화를 위한 빈 이미지 생성
line_image = np.zeros_like(rotated_image)
# 검출된 선분을 시각화
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(line_image, (x1, y1), (x2, y2), (0, 255, 0), 2)
# 선분이 그려진 이미지와 원본 이미지를 합성
final_image = cv2.addWeighted(rotated_image, 0.8, line_image, 1, 0)
else:
final_image = image
mod_type = '1'
except:
# Contour 추출
contours, _ = cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# edges 중 가장 큰 영역의 외곽 사각형 추출
contour = max(contours, key=cv2.contourArea)
rect = cv2.minAreaRect(contour)
box = cv2.boxPoints(rect)
box = np.int0(box)
# 사각형 그리기
final_image = cv2.drawContours(image, [box], 0, (0, 255, 0), 2)
# 각도 계산
angle = rect[-1]
# 반대 방향 각도 계산
reverse_angle = 90 - abs(angle)
if abs(angle) <= reverse_angle:
if angle <= reverse_angle:
final_angle = angle
status = 'a.a <= r | a <= r'
else:
final_angle = angle
status = 'a.a <= r | a >= r'
# abs(angle) > reverse_angle:
else:
if angle <= reverse_angle:
final_angle = reverse_angle
status = 'a.a > r | a <= r'
else:
final_angle = -(reverse_angle)
status = 'a.a > r | a >= r'
if reverse_angle != 0:
# 회전 중심 설정
(h, w) = image.shape[:2]
center = (w // 2, h // 2)
# 회전 각도 계산 및 이미지 회전
rotation_matrix = cv2.getRotationMatrix2D(center, final_angle, 1.0)
rotated_image = cv2.warpAffine(image, rotation_matrix, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_CONSTANT, borderValue=(255, 255, 255))
final_image = rotated_image
else:
final_image = image
mod_type = '2'
# 이미지를 3x3 배열에 출력
row_index = i // 3
col_index = i % 3
axes[row_index, col_index].imshow(cv2.cvtColor(final_image, cv2.COLOR_BGR2RGB))
axes[row_index, col_index].axis('off')
# 파일명과 각도 표시
filename = image_path.split('\\')[-1]
axes[row_index, col_index].text(0, -20, f"{filename} \n Angle: {angle:.2f} \n reverse_Angle: {reverse_angle:.2f} \n final_Angle: {final_angle:.2f} \n mod_type : {mod_type} \n status : {status}" , color='red', fontsize=8, ha='left', va='top')
plt.show()