ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 7/1 - (7/10000)
    개발일지 2024. 7. 1. 23:43


    nuscene의 구조에 대해서 정리하려고 했는데 딴것하느라 못했음.

     

    6개 이미지를 합성해서 그리고 그것을 object detection 을 해보고

     

    내가 보고 싶은 label 만 골라서 보는 시뮬레이션이다.

     

    import os
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    import torch
    from torchvision.models.detection import fasterrcnn_resnet50_fpn
    from torchvision import transforms
    from PIL import Image
    # NuScenes 데이터셋 경로
    nusc_data_dir = '/data/sets/nuscenes/samples/'
    
    # 각 카메라 폴더
    camera_folders = ['CAM_FRONT_LEFT','CAM_FRONT', 'CAM_FRONT_RIGHT', 'CAM_BACK_LEFT','CAM_BACK', 'CAM_BACK_RIGHT']
    
    
    coco_classes = [
        "__background__", "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat",
        "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep",
        "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
        "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
        "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich",
        "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch", "potted plant", "bed",
        "dining table", "toilet", "TV", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave", "oven",
        "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush"
    ]
    
    def extract_number(filename, name ):
        try:
            number_str = filename.split(f'__{name}__')[1].split('.')[0]
            return int(number_str)
        except IndexError:
            return None  # "__CAM_BACK__" 뒤에 숫자가 없는 경우 처리
        
    # 이미지 리사이즈 크기 (옵션)
    resize_dim = (640, 480)  # 원하는 크기로 설정
    
    # 결과 저장 디렉토리
    output_dir = './combined_images'
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    
    # 폴더별 이미지 읽기 및 처리
    folder_images = []
    # 모든 이미지를 읽어서 좌우 반전 후 조합
    combined_images = []
    for folder in camera_folders:
        img_path = os.path.join(nusc_data_dir, folder)
        images = []
        files = os.listdir(os.path.join(nusc_data_dir, folder))
        # 파일 이름에서 숫자를 추출하여 정렬하기
        sorted_files = sorted(files, key=lambda x: extract_number(x,folder) or float('inf'))    
        
        for filename in sorted_files:  # 파일 이름 순으로 정렬
            if filename.endswith('.jpg'):
                img = cv2.imread(os.path.join(img_path, filename))
                if img is not None:
                    img = cv2.resize(img, resize_dim)  # 이미지 리사이징
                    # CAM_BACK 카메라만 좌우 반전
                    if 'CAM_BACK' in folder:
                        img = cv2.flip(img, 1)
                    images.append(img)
                else:
                    print(f"Error reading image from {filename}")
        folder_images.append(images)
        
    # # 각 폴더의 이미지를 위아래로 합치기
    combined_images = []
    for imgs in zip(*folder_images):
            # 좌우로 3개씩 묶어서 합치기
        combined_row1 = np.hstack(imgs[:3])
        combined_row2 = np.hstack(imgs[3:])
        combined_image = np.vstack([combined_row1, combined_row2]) 
        combined_image2 = cv2.cvtColor(combined_image, cv2.COLOR_BGR2RGB)
        combined_images.append(combined_image)
        
    # 사전 학습된 Faster R-CNN 모델 로드
    model = fasterrcnn_resnet50_fpn(pretrained=True)
    model.eval()
    
    # 이미지 전처리
    transform = transforms.Compose([transforms.ToTensor()])
    
    def detect_objects(image):
        image_tensor = transform(image).unsqueeze(0)
        with torch.no_grad():
            predictions = model(image_tensor)
        return predictions[0]
    
    def visualize_predictions(image, predictions,target_classes, score_threshold=0.5):
        plt.cla()
        plt.imshow(image)
        plt.axis('off')
        
        for box, label, score in zip(predictions['boxes'], predictions['labels'], predictions['scores']):
            if score > score_threshold and label in target_classes:
                x1, y1, x2, y2 = box
                plt.gca().add_patch(plt.Rectangle((x1, y1), x2-x1, y2-y1, edgecolor='red', facecolor='none', linewidth=2))
                
               # 라벨 숫자 그리기
                plt.text(x1, y1, f'{coco_classes[label]}', fontsize=12, bbox=dict(facecolor='yellow', alpha=0.5))
                
        
        plt.pause(1)  # Pause to update the plot
    
    plt.figure(figsize=(10, 5))
    
    
    # for channel, img in enumerate(combined_images['combined']):
    target_classes = [0,1,2,3,4,6,7,8,9,10,11,12,13,14,15,16,17]
    for channel, img in enumerate(combined_images):
        img_pil = Image.fromarray(img)
        predictions = detect_objects(img_pil)
        print(f"Predictions for {channel}:")
        visualize_predictions(img, predictions,target_classes)
        
    plt.show()

     

     

    전반적으로 잘되나 car 잘못 분류하는 것도 볼 수 있다. 

     

     

     

     

    이미지를 클래스 분류하는 과정 아래와 같다.

     

    이미지 준비

     

    // pil 파입 변환

    img_pil = Image.fromarray(img)

     

    //전처리 함

    image_tensor = transform(image).unsqueeze(0)

     

    // 모델 실행

    predictions = model(image_tensor)

     

    // 조건을 통한 의미 있는 정보 추출

    if score > score_threshold and label in target_classes:

     

    전처리 의미

    1. transform(image):
      • transform은 이미지를 텐서로 변환하고, 추가적인 전처리를 수행하는 함수나 파이프라인입니다.
      • 일반적으로 PyTorch에서 이미지 전처리 파이프라인은 torchvision.transforms 모듈을 사용하여 정의합니다. 예를 들어, 이미지를 텐서로 변환하고, 크기를 조정하고, 정규화하는 등의 작업을 수행할 수 있습니다.
      • 예시: 

      • from torchvision import transforms transform = transforms.Compose([ transforms.ToTensor(), # 이미지를 PyTorch 텐서로 변환 transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) # 이미지 정규화 ])
    2. .unsqueeze(0):
      • PyTorch 텐서의 차원을 추가합니다.
      • Faster R-CNN과 같은 모델은 배치(batch) 단위로 입력을 받습니다. 즉, 모델 입력은 [batch_size, channels, height, width] 형태여야 합니다.
      • transforms.ToTensor()를 사용하면 [channels, height, width] 형태의 텐서가 생성됩니다.
      • .unsqueeze(0)는 첫 번째 차원에 배치 크기(dim=0)를 추가하여 [1, channels, height, width] 형태로 만듭니다.

    왜 필요한가?

    1. 이미지 전처리:
      • 모델에 이미지를 입력하기 전에 이미지를 텐서로 변환하고 정규화합니다. 이는 모델이 학습된 데이터 분포와 입력 이미지의 분포를 맞추기 위해 필요합니다.
      • 정규화를 통해 픽셀 값을 일정 범위로 맞춤으로써 학습의 안정성을 높입니다.
    2. 배치 차원 추가:
      • PyTorch 모델은 배치 형태의 입력을 기대합니다. 단일 이미지를 모델에 넣기 위해서는 배치 차원을 추가하여 [1, channels, height, width] 형태로 만들어야 합니다.

     

    추가 설명 :

     

    코드를 보면  zip()을 많이 사용하는데 정리를 해보자~~~

     

    즉  zip(a,b) 이렇게 사용하거나, zip(*a) 이렇게 보통 사용하는데 2가지 사용법에 대해서 아래 예시를 보면 이해가 갈것이다.

    두 리스트를 묶어서 순회하기
    
    코드
    list1 = [1, 2, 3]
    list2 = ['a', 'b', 'c']
    
    zipped = zip(list1, list2)
    print(list(zipped))
    
    결과
    [(1, 'a'), (2, 'b'), (3, 'c')]
    
    
    코드
    names = ['Alice', 'Bob', 'Charlie']
    scores = [85, 90, 95]
    
    for name, score in zip(names, scores):
        print(f"{name}: {score}")
    
    결과
    Alice: 85
    Bob: 90
    Charlie: 95
    
    언패킹과 함께 사용하기
    zip() 함수로 묶은 것을 언패킹하여 원래의 리스트로 되돌릴 수도 있습니다.
    예시)
    zipped = [('a', 1), ('b', 2), ('c', 3)]
    letters, numbers = zip(*zipped)
    print(letters)  # ('a', 'b', 'c')
    print(numbers)  # (1, 2, 3)
    반응형

    '개발일지' 카테고리의 다른 글

    7/10 - [11/10K] - nuscene 이미지 저장  (0) 2024.07.10
    7/9 - (9/10K)  (0) 2024.07.10
    6/30 - (5/10000)  (1) 2024.06.30
    6/29 - (4/10000)  (0) 2024.06.29
    6/28 - (2/10000)  (0) 2024.06.28
Designed by Tistory.