영상처리 프로그램 작성하면서 OpenCV 라이브러리를 많이 사용함

C++에서 지원되는 라이브러리 였는데, Python에서도 잘 됨

그래서, Python 사용할 줄 아는 사람들이 이미지 관련 프로그래밍 할 때 자주 사용함

Python의 OpenCV는 사실 C++ 라이브러리가 내장된 것임.

무슨 말이냐면, Python에서 OpenCV 함수를 호출하면, 해당되는 C++ OpenCV 함수가 호출되는 것임.

Python으로 작성한 이미지 프로그램과 C++로 동일한 것을 작성한 것 중 어느 것이 빠를까 하는 질문이 생긴다면,

당연히도, C++로 작성한 것이 조금 더 빠르지 않을까 예상하게 됨.

Python에서 C++ 라이브러리를 호출하는 오버헤드를 고려하면 당연한 예상임.

그런데, 예상이 늘 맞지는 않음.

간단한 예제 프로그램으로 실험을 해 보았음.

이것은 이미지 한 장을 읽어 들인 후에, 여기에 Gaussian blurring 을 500번 반복 적용하는 것임.

Gaussian blurring은 이미지 효과 처리 방법 하나로, 이미지를 흐릿하게 (blurring) 하는 것임.

이 프로그램을 python과 C++로 작성해 보았음.


Windows 11 환경에서 Python은 Visual studio code, C++는 Visual studio 2022에서 작성하였음.

Python은 3.12 버전에 OpenCV 4.10을 pip로 설치하였음.

C++도 OpenCV 4.10 compiled version을 다운로드 받아서 설치하였음.

특히, C++는 release 모드로 컴파일 하였음.


아래는 Python으로 작성한 것임. 

import cv2
import time

# Load image
image = cv2.imread("test.jpg")

# Start timer
start = time.time()

# Apply Gaussian Blur 500 times
for _ in range(500):
    image = cv2.GaussianBlur(image, (5, 5), 0)

# End timer
end = time.time()

print(cv2.getBuildInformation())
print(f"Time elapsed: {end - start:.4f} seconds")

test.jpg 사진을 읽어들여, 반복적으로 Gaussian blurring을 500번 적용하는데 걸리는 시간을 측정하는 것임.

test.jpg 사진의 크기는 대출 1400 x 1600 정도되는 컬러 사진임.

 


아래는 동일한 일을 수행하는 C++ 프로그램임.

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

using namespace std;

int main() {

    // Load image
    cv::Mat image = cv::imread("test.jpg");
    if (image.empty()) {
        std::cerr << "Image not found!" << std::endl;
        return -1;
    }

    // Start timer
    auto start = std::chrono::high_resolution_clock::now();

    // Apply Gaussian Blur 500 times
    for (int i = 0; i < 500; ++i) {
        cv::GaussianBlur(image, image, cv::Size(5, 5), 0);
    }

    // End timer
    auto end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> elapsed = end - start;

    std::cout << "Time elapsed: " << elapsed.count() << " seconds" << std::endl;
    return 0;
}

수행시간은 Python 0.80 ~ 0.89초, C++ 1.2~1.3초 정도가 나옴. 

Python과 C++ 둘 다 같은 컴퓨터에서 여러 번 반복 실험하였음.

예상과 다르게 Python이 더 빠름.

Blurring 반복 회수를 500번에서 5,000번으로 증가시켜면, 소요되는 시간이 10배씩 증가함

그러나, Python과 C++의 격차는 줄어들지 않음.


이유를 검색해 보았음

Python이 사용하는 opencv-python 패키지가 고도로 최적화된 C++ 라이브러리일 가능성이 높다고 함.

따라서, Python에서 C++ 호출하는 오버헤드를 상쇄시키고도 남을 수 있다고 함.


OpenCV-Python을 깔보면 안 됨. 양(Python)의 탈을 쓴 호랑이(C++)가 opencv-python 임. 

반응형
LIST

개요

 

문자열에서 내가 원하는 정보만을 추출해 낼 때, 정규식 (regular expression)을 사용하면 편리하다.


 

문제

다음과 같은 문자열 S가 있다고 하자.

2022-07-28 14:06:24;[DEBUG]    Epoch 9 학습시작. LR=[2.4471741852423235e-05]

 

S에는 epoch에 대한 정보와 LR에 대한 정보가 담겨있다.

즉, epoch=9, LR=2.44... 이다.

S를 파싱해서 이 정보들만을 추출해 보도록 하자.


구현

 

- 정규식을 이용하려면 모듈 re가 필요하다.

import re

 

- 정보를 담고 있는 문자열 S를 만든다.

S = '2022-07-28 14:06:24;[DEBUG]    Epoch 9 학습시작. LR=[2.4471741852423235e-05]'

 

- 추출하고 싶은 정보가 무엇인지, 정규식으로 표현한다.

regex = re.compile(r'Epoch (\d+)')

    . Epoch 이라는 문자열이 있고, 

    . \d 는 0 ~ 9까지의 숫자를 의미

    . \d+ 는 1개 이상의 숫자로 구성된 문자열을 의미

    . (\d+) 는 ( )는 내가 추출을 원하는 정보임을 표시

    . regex에는 추출하고자 하는 것이 무엇인지에 대한 정보가 담긴다.

 

- regex를 이용해서 S를 검색한다. 

matchobj = regex.search(S)

    . matchobj에는 추출 결과들이 담겨있다.

 

- matchobj에서 내가 원하는 정보만을 꺼내면 된다.

epoch = int(matchobj.group(1))

    . matchobj.group(1)은 추출된 것 중에서 첫 번째 정보를 의미한다.

    . int ( ...) 는 추출된 것이 문자열이기 때문에 정수로 변환

 

- 이번에는 LR 정보를 추출하기 위한 정규식을 만들어 보자

regex = re.compile(r'LR=\[(.+)\]')

    . \[, \]는 양 옆의 괄호 문자를 의미한다.

    . .(period)는 모든 문자를 의미

    . .+ : 1개 이상의 모든 문자.

 

- LR을 추출하는 코드는 위와 동일하다.

matchobj = regex.search(S)
lr = float(matchobj.group(1))

    . float( )는 추출된 문자열을 실수로 바꾸어주는 것이다.

 


아래는 regular expression(정규식)에서 사용되는 meta characters(메타 문자)들이다.

반응형
LIST

+ Recent posts