OpenCV 픽셀 접근 속도 테스트

픽셀단위에 접근하여 연산할 때 가장 어떤 방법이 가장 빠른가?

결론 :

  • 순차처리
    • atFunc : 2.0873msec.
    • dataPtr : 1.4164msec.
    • ptrFunc : 1.1877msec.
    • ptr++ : 0.2126msec.
  • 병렬처리
    • parallel_for dataPtr : 0.393msec.
    • parallel_for ptr: 0.2211msec.
    • parallel_for Optimize: 0.0557msec.
```cpp

#include <iostream>
#include <stdio.h>
#include "opencv2/opencv.hpp"
#include <ppl.h>

int main()
{
    //화면을 표시할 윈도우 설정
    std::string wndName = "Color Test";
    namedWindow(wndName, cv::WINDOW_NORMAL);
    cv::setWindowTitle(wndName, "Color Test");

    //mnms이미지 불러오기
    cv::Mat OriginImg = cv::imread("../images/mnms.png",cv::IMREAD_GRAYSCALE);
    cv::Mat TestImg = OriginImg;

    //원본 이미지 출력
    cv::imshow(wndName, OriginImg);
    cv::waitKey(0);
    cv::destroyWindow(wndName);

    //이미지의 모든 픽셀을 순회할 때 소요된 시간을 측정해본다.

    //시작,종료 시간을 기록하기 위한 timer
    cv::TickMeter tm;

#pragma region atFunc
    tm.reset();
    tm.start();
    for (int y = 0; y < TestImg.rows; ++y)
    {
        for (int x = 0; x < TestImg.cols; ++x)
        {
            uchar val = TestImg.at<uchar>(y, x);
            TestImg.at<uchar>(y, x) = val + 1;
        }
    }
    tm.stop();
    std::cout << "atFunc : " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

#pragma region dataPtr
    tm.reset();
    tm.start();

    uchar* pTestImg = TestImg.data;
    for (int y = 0; y < TestImg.rows; ++y)
    {
        for (int x = 0; x < TestImg.cols; ++x)
        {
            uchar val = pTestImg[TestImg.rows * y + x];
            pTestImg[x] = val + 1;
        }
    }
    tm.stop();
    std::cout << "dataPtr : " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

#pragma region ptr
    tm.reset();
    tm.start();

    for (int y = 0; y < TestImg.rows; ++y)
    {
        //Test이미지의 행의 시작 주소를 가져옴
        uchar* pImg = TestImg.ptr<uchar>(y);

        //행의 시작에서 하나씩 증분하여 한 행의 끝까지 데이터 탐색
        for (int x = 0; x < TestImg.cols; ++x)
        {
            uchar val = pImg[x];
            pImg[x] = val + 1;
        }
    }
    tm.stop();
    std::cout << "ptrFunc : " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

#pragma region ptr++
    tm.reset();
    tm.start();

    for (int y = 0; y < TestImg.rows; ++y)
    {
        //Test이미지의 행의 시작 주소를 가져옴
        uchar* pSrc = TestImg.ptr<uchar>(y);

        //Test이미지의 행의 마지막 주소를 가져옴
        uchar* pSrc_end = pSrc + TestImg.cols;

        //한행의 끝이 나올때까지 반복
        for (; pSrc < pSrc_end;)
        {
            uchar val = *pSrc;
            //후치 연산자로 val값 업데이트 후 포인터 위치변경
            *pSrc++ = val + 1;
        }
    }  
    tm.stop();
    std::cout << "ptr++ : " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

#pragma region parallel_for dataPtr
    tm.reset();
    tm.start();
    uchar* pSrc = TestImg.data;
    Concurrency::parallel_for(int(0), TestImg.rows, [&](int y)
    {
        for (int x = 0; x < TestImg.cols; ++x) {
            uchar val = pSrc[TestImg.cols * y + x];
            pSrc[TestImg.cols * y + x] = val + 1;
        }
    });
    tm.stop();
    std::cout << "parallel_for dataPtr : " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

#pragma region parallel_for ptr
    tm.reset();
    tm.start();
    Concurrency::parallel_for(int(0), TestImg.rows, [&](int y)
    {
        uchar* pSrc = TestImg.ptr<uchar>(y);
        for (int x = 0; x < TestImg.cols; ++x) {
            uchar val = pSrc[x];
            pSrc[x] = val + 1;
        }
    });
    tm.stop();
    std::cout << "parallel_for ptr: " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

#pragma region parallel_for ptr++
    tm.reset();
    tm.start();
    concurrency::parallel_for(int(0), TestImg.rows, [&](int y)
    {
        uchar* pSrc = TestImg.ptr<uchar>(y);
        uchar* pSrc_end = pSrc + TestImg.cols;
        for (; pSrc < pSrc_end;) {
            uchar val = *pSrc;
            *pSrc++ = val + 1;
        }
    });
    tm.stop();
    std::cout << "parallel_for Optimize: " << tm.getTimeMilli() << "msec." << std::endl;
#pragma endregion

    return 0;
}
```

OpenCV 기본 세팅 Setting

OpenCV를 Visual Studio에서 사용하기 위한 기본 Setting 과정

※opencv 설치 경로 : C:\

※opencv 버전 : opencv-4.8.0-windows

  1. 아래와 같이 새 프로젝트를 생성한다.

  1. 아래와 같이 소스파일 폴더 아래 Main.cpp 파일을 하나 생성한다.

  1. OpenCV_Vision 프로젝트의 속성으로 들어간 후 구성(C): 모든구성, 플랫폼(P) : x64 로 설정

  1. opencv가 설치된 경로를 추가한다. 공통설정4-3. 디버깅항목에 환경에 DLL경로를 입력 PATH = C:\opencv\build\x64\vc16\bin;%PATH%4-4. 구성-Debug 추가종속성에 opencv_world480d.lib 입력
  2. 4-2. 링커의 추가 라이브러리 디렉터리에 C:\OpenCV\build\x64\vc16\lib 입력 : 링커를 포함시킴
  3. 4-1. C/C++의 추가 포함 디렉터리에 C:\opencv\build\include 입력 : 헤더파일을 포함하는 것
  1. OpenCV_Vision 프로젝트의 속성으로 들어간 후 구성(C): Debug, 플랫폼(P) : x64 로 설정
  2. 5-1. 추가 종속성 항목에 opencv_world480d.lib 입력
  1. OpenCV_Vision 프로젝트의 속성으로 들어간 후 구성(C): Release, 플랫폼(P) : x64 로 설정
  2. 6-1. 추가 종속성 항목에 opencv_world480.lib 입력
  3. 정상적으로 세팅이 되었는지 샘플코드 입력 후 빌드/실행하여 확인한다.7-3. 샘플코드
  4. /** @file videocapture_basic.cpp @brief A very basic sample for using VideoCapture and VideoWriter @author PkLab.net @date Aug 24, 2016 */ #include <opencv2/core.hpp> #include <opencv2/videoio.hpp> #include <opencv2/highgui.hpp> #include <iostream> #include <stdio.h> using namespace cv; using namespace std; int main(int, char**) { Mat frame; //--- INITIALIZE VIDEOCAPTURE VideoCapture cap; // open the default camera using default API // cap.open(0); // OR advance usage: select any API backend int deviceID = 0; // 0 = open default camera int apiID = cv::CAP_ANY; // 0 = autodetect default API // open selected camera using selected API cap.open(deviceID, apiID); // check if we succeeded if (!cap.isOpened()) { cerr << "ERROR! Unable to open camera\n"; return -1; } //--- GRAB AND WRITE LOOP cout << "Start grabbing" << endl << "Press any key to terminate" << endl; for (;;) { // wait for a new frame from camera and store it into 'frame' cap.read(frame); // check if we succeeded if (frame.empty()) { cerr << "ERROR! blank frame grabbed\n"; break; } // show live and wait for a key with timeout long enough to show images imshow("Live", frame); if (waitKey(5) >= 0) break; } // the camera will be deinitialized automatically in VideoCapture destructor return 0; }
  5. 7-2. 활성상태를 Release, x64로 설정 후 빌드
  6. 7-1. 활성상태를 Debug, x64로 설정 후 빌드

'OpenCV' 카테고리의 다른 글

OpenCV 픽셀 접근 속도 테스트  (0) 2024.05.11

+ Recent posts