비디오 코덱

흑백 변환 : cvtColor() vs imread()

케케_ 2024. 11. 27. 13:58

지피티 답변

 

cv::cvtColor를 사용해서 흑백으로 변환하는 방법과 cv::imread 함수에서 0을 사용하여 이미지를 흑백으로 불러오는 방법은 결과적으로 눈으로 봤을 때는 동일하게 보일 수 있지만, 작동 방식과 활용 목적에서 차이가 있습니다. 아래에서 두 방법을 비교하겠습니다.


1. cv::imread에서 0으로 흑백 불러오기

cv::Mat img = cv::imread("image.jpg", 0);

작동 방식

  • cv::imread의 두 번째 매개변수로 0을 전달하면 OpenCV는 이미지를 바로 Grayscale로 불러옵니다.
  • 이 경우:
    • 이미 파일에서 데이터를 읽을 때 이미지를 Grayscale로 변환.
    • 메모리에 1채널 Grayscale 데이터로 직접 저장.

장점

  • 불필요한 컬러 데이터를 메모리에 로드하지 않아 더 빠르고 효율적.
  • 이미 흑백으로 처리된 이미지를 다루는 경우 적합.
  • 이미 로드 시점부터 Grayscale이므로 추가 변환 작업이 필요 없음.

2. cv::cvtColor로 흑백 변환

cv::Mat colorImg = cv::imread("image.jpg"); // BGR 이미지 로드
cv::Mat grayImg;
cv::cvtColor(colorImg, grayImg, cv::COLOR_BGR2GRAY); // Grayscale 변환

작동 방식

  • 원본 이미지를 컬러(BGR)로 로드한 후, cv::cvtColor를 사용해 Grayscale로 변환.
  • 변환 과정에서 OpenCV는 다음과 같은 수식을 적용해 RGB 값을 단일 Grayscale 값으로 계산:
    [
    {Gray} = 0.299 * R + 0.587 * G + 0.114 * B
    ]
  • 컬러 이미지의 모든 픽셀 정보를 기반으로 계산된 Grayscale 값으로 변환.

장점

  • 컬러 정보가 필요한 작업 후에 Grayscale 변환이 가능.
    • 예: 특정 컬러 기반 분석 후 Grayscale로 변환.
  • 동일 이미지를 컬러와 Grayscale 두 가지로 처리해야 할 때 적합.

3. 주요 차이점 비교

구분 cv::imread (0) cv::cvtColor
입력 이미지 형태 바로 Grayscale로 불러옴 (1채널) 컬러(BGR)로 불러온 후 Grayscale로 변환
속도 빠름 (직접 Grayscale 로드) 약간 느림 (추가 변환 단계 필요)
메모리 사용량 적음 (1채널만 저장) 높음 (컬러 → Grayscale 변환 후 1채널)
활용 목적 단순히 Grayscale 이미지가 필요할 때 적합 컬러 데이터를 활용한 후 Grayscale 변환
변환 수식 적용 Grayscale로 바로 저장 (수식이 다를 수도 있음) 명시적 수식 적용 (0.299R + 0.587G + 0.114B)

4. 눈으로 봤을 때 차이가 없는 이유

  • cv::imread0 옵션과 cv::cvtColor의 Grayscale 변환 모두 Grayscale 데이터를 생성하므로, 결과적으로 이미지의 시각적인 표현은 동일하게 보입니다.
  • 하지만 내부 처리 방식은 다릅니다:
    • cv::imread(0)은 단순히 파일에서 읽으면서 픽셀 값을 Grayscale로 변환해 바로 저장.
    • cv::cvtColor는 컬러 데이터를 기반으로 가중치를 적용하여 더 정밀하게 Grayscale로 변환.

5. 어느 것을 사용할까?

cv::imread (0) 사용이 적합한 경우

  • 이미 Grayscale 처리된 이미지를 바로 불러오고 싶을 때.
  • 성능이 중요한 경우:
    • 컬러 데이터를 사용하지 않고, 바로 Grayscale로 작업하는 경우.
  • 예:
    • OCR(문자 인식), 흑백 이미지만 다루는 알고리즘.

cv::cvtColor 사용이 적합한 경우

  • 원본 컬러 데이터를 기반으로 추가 작업 후 흑백 변환이 필요한 경우.
  • 컬러와 Grayscale 두 가지 데이터가 모두 필요한 경우.
  • 예:
    • 컬러 정보 기반 객체 탐지 후 흑백으로 변환해 추가 처리.

6. 성능 차이 테스트

간단한 성능 비교 코드를 작성하여 두 방법의 차이를 테스트할 수 있습니다:

#include <opencv2/opencv.hpp>
#include <iostream>
#include <chrono>

int main() {
    // 파일 경로
    std::string file = "image.jpg";

    // cv::imread로 Grayscale 로드
    auto start = std::chrono::high_resolution_clock::now();
    cv::Mat gray1 = cv::imread(file, 0);
    auto end = std::chrono::high_resolution_clock::now();
    std::cout << "cv::imread(0): "
              << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count()
              << " microseconds" << std::endl;

    // cv::cvtColor로 Grayscale 변환
    start = std::chrono::high_resolution_clock::now();
    cv::Mat color = cv::imread(file);
    cv::Mat gray2;
    cv::cvtColor(color, gray2, cv::COLOR_BGR2GRAY);
    end = std::chrono::high_resolution_clock::now();
    std::cout << "cv::cvtColor: "
              << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count()
              << " microseconds" << std::endl;

    return 0;
}

 

결과

➜  build git:(main) ✗ ./main
cv::imread(0): 118450 microseconds
cv::cvtColor: 205848 microseconds

 


결론

  • 눈으로 보기에 차이가 없는 것은 두 방법 모두 최종적으로 Grayscale 이미지를 생성하기 때문입니다.
  • 그러나 cv::imread(0)는 파일을 읽을 때 바로 Grayscale로 불러오는 방식이고, cv::cvtColor는 컬러 데이터를 활용한 후 변환하기 때문에 용도와 내부 동작에서 차이가 있습니다.

추가 질문이 있거나 특정 상황에 대해 더 깊이 알고 싶다면 말씀해주세요! 😊