OpenCV 성능향상을 위한 포인터(Pointer) 사용
함수 at( )의 문제점
이미지의 각 픽셀값을 바꿀 때
함수 at( )을 사용했다.
기능상으로는 아무 문제가 없지만, 속도가 느린 단점이 있다.
예를 들어, 다음과 같은 컬러이미지를 반전하는 경우를
생각해보자.
원본 컬러영상
반전한 컬러이미지
함수 at( )을 이용한 이미지 반전코드
for (int r = 0; r < image_rows; r++) { for (int c = 0; c < image_cols; c++) { for (int ch = 0; ch < 3; ch++) { outputImg.at<Vec3b>(r, c)[ch] = 255 - outputImg.at<Vec3b>(r, c)[ch]; } } }
각 픽셀에 대해,
픽셀별로 R, G, B 채널에 대해서 반전시키면 된다.
그런데, 사실 이 방법은
시간이 오래 걸린다.
시간측정방법
코드가 수행하는데 걸리는 시간을 측정하기 위해서는
함수 getTickCount( )를 이용하면 된다.
const int64 start = getTickCount(); ..... int64 elapsed = (getTickCount() - start);
함수 at( )을 이용하여, 반전이미지 만드는데 걸리는 시간
함수 getTickCount( )를 이용해서
측정한 시간은 평균적으로 210,000 tick 정도 된다.
포인터를 이용한 속도 개선
함수 at ( )을 사용하지 않고,
이미지 데이터에 대해 포인터를 이용하여 직접 픽셀값을
바꾸면 속도를 엄청나게 개선시킬 수 있다.
for (int r = 0; r < image_rows; r++) { uchar* value = inputImg.ptr<uchar>(r); uchar* result = outputImg.ptr<uchar>(r); for (int c = 0; c < image_cols; c++) { *result++ = *value++ ^ 0xff; *result++ = *value++ ^ 0xff; *result++ = *value++ ^ 0xff; } }
위의 코드는 반전이미지를 동일한 방식으로 만들되,
포인터를 이용하여 각 픽셀값을 직접 접근하는 방식이다.
이렇게 했을 때, 측정시간은
평균적으로 4,300 tick이다.
비교 그래프
아래는 함수 at( )과 포인터를 이용했을 때의
각각의 소요시간이다.
포인터를 이용했을 때, 약 50배 정도 속도가 빨라지는 것을 알 수 있다.
따라서, 성능이 중요할 경우에는 포인터 사용을 적극 고려해야 한다.
소스코드
위의 실험수행을 위한 프로그램이다.
중간에 매크로 USE_AT을 #define하면 함수 at( )을 이용하는 방식으로 동작하고,
comment-out하면 포인터를 이용한 방식으로 동작한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, char** argv) { if (argc != 2) { cout << " Provide image name to read" << endl; return -1; } Mat inputImg; Mat outputImg; inputImg = imread(argv[1], CV_LOAD_IMAGE_COLOR); outputImg = inputImg.clone(); const int64 start = getTickCount(); int image_rows = inputImg.rows; int image_cols = inputImg.cols; //#define USE_AT #ifdef USE_AT for (int r = 0; r < image_rows; r++) { for (int c = 0; c < image_cols; c++) { for (int ch = 0; ch < 3; ch++) { outputImg.at<Vec3b>(r, c)[ch] = 255 - outputImg.at<Vec3b>(r, c)[ch]; } } } #else if for (int r = 0; r < image_rows; r++) { uchar* value = inputImg.ptr<uchar>(r); uchar* result = outputImg.ptr<uchar>(r); for (int c = 0; c < image_cols; c++) { *result++ = *value++ ^ 0xff; *result++ = *value++ ^ 0xff; *result++ = *value++ ^ 0xff; } } #endif int64 elapsed = (getTickCount() - start); cout << "Elapsed time " << elapsed << endl; namedWindow("input", CV_WINDOW_AUTOSIZE); namedWindow("output", CV_WINDOW_AUTOSIZE); moveWindow("input", 100, 100); moveWindow("output", 120, 120); imshow("input", inputImg); imshow("output", outputImg); waitKey(0); return 0; } |
'Computer Vision by OpenCV' 카테고리의 다른 글
OpenCV HLS형식의 이미지 채널별 분리 (Split HLS-formated image) (0) | 2016.03.19 |
---|---|
OpenCV YUV형식의 이미지 분리 (Split YUV-formated image) (0) | 2016.03.19 |
컬러이미지를 색깔별로 구분하기 (Split color image into R, G, B images) (0) | 2016.03.19 |
이미지 반전하기 (Invert Color Image) (0) | 2016.03.18 |
Webcam 영상을 Grey로 출력하기 (0) | 2016.03.16 |