본문 바로가기

카테고리 없음

4/11~4/22 :: Rectification

  • cv2.HoughLinesP 및 object contour boxing 활용하여 직선만 추출
    • 방법 1. 추출된 직선을 기준으로 이미지를 회전하여 변형
      • 회전된 이미지에 직선을 시각화(변화 비교용)
    • 방법 2. 직선 추출 불가시 object contour boxing 기법 사용

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()