2014-09-14 6 views
1

제 경우에는 행 벡터가 될 수있는 특정 요소를 찾으려고합니다. (보다 일반적인 경우 매트는 둘 이상의 차원 일 수 있습니다). 대상의 데이터 유형은 char, int, double 등으로 간단 할 수 있습니다.OpenCV Mat에서 요소를 효율적으로 찾습니다.

std :: vector에서 요소를 찾는 방법을 설명하는 기존 게시물이 있습니다 (How to find if an item is present in a std::vector?). 따라서이를 수행하는 한 가지 방법은 다음과 같습니다. 1) cv :: Mat를 std :: vector로 변환합니다. 2) 게시물에서 메소드를 사용하여 요소를 찾습니다. 그러나이 검색 작업을 행 당 수백 번 수행해야합니다. 수백 개의 행을 처리해야 할 때 성능이 문제가 될 수 있습니다.

나는 위의 방법 (변환 + 검색)의 성능에 대해 궁금해하고 있습니다. 변환을하지 않고 cv :: Mat를 사용하여 직접 요소를 검색 할 수있는 더 효율적인 방법이 있습니까?

p.s : 여기에 두 답변을 결합하고, 매트 종류에 따라 Converting a row of cv::Mat to std::vector

+0

정확하게 'find element'는 무엇을 의미합니까? 바이너리 응답이 필요합니까 (예 : '17'이 포함되어 있습니까?)? 색인 목록? x, y 위치? 발생 카운트 ('i == 17)? – berak

+0

매트에있는 대상의 x, y 위치 (내 경우에는 단지 1 차원 위치)를 원했습니다. @marol은 색인을 쉽게 얻기 위해 수정 될 수있는 이진 버전의 응답을 제공했습니다. –

답변

4

에 대한 게시물은 (여기 CV_64F) 당신이 얻을 :

bool findValue(const cv::Mat &mat, double value) { 
    for(int i = 0;i < mat.rows;i++) { 
     const double* row = mat.ptr<double>(i); 
     if(std::find(row, row + mat.cols, value) != row + mat.cols) 
      return true; 
    } 
    return false; 
} 

(자세한 내용은 find docs 참조). 물론 매트 행을 벡터로 변환 한 다음 해당 벡터에서 std :: find를 사용하면 행 배열에 대한 포인터에서 직접 find를 사용하는 것보다 속도가 느립니다.

편집 : 좀 더 복잡한 데이터 유형에 그것을 테스트

template <class T> 
bool findValue(const cv::Mat &mat, T value) { 
    for(int i = 0;i < mat.rows;i++) { 
     const T* row = mat.ptr<T>(i); 
     if(std::find(row, row + mat.cols, value) != row + mat.cols) 
      return true; 
    } 
    return false; 
} 

: : 좀 더 연구 후에는 제네릭을 개발하는 것은 매우 어려운 일이 아니다 놀라게

cv::Mat matDouble = cv::Mat::zeros(10, 10, CV_64F); 
cv::Mat matRGB = cv::Mat(10, 10, CV_8UC3, cv::Scalar(255, 255, 255)); 

std::cout << findValue(matDouble, 0.0) << std::endl; 
std::cout << findValue(matDouble,1.0) << std::endl; 
std::cout << findValue(matRGB, cv::Scalar(255, 255, 255)) << std::endl; 
std::cout << findValue(matRGB, cv::Scalar(255, 255, 254)) << std::endl; 

그리고 무엇 나 출력은 다음과 같습니다.

1 
0 
0 // should be 1, right? 
0 

문제는 cv :: Scalar 크기 구조 때문입니다. 우리가 사용하는 생성자의 버전에 관계없이 (즉, 하나, 둘, 셋 또는 네 개의 인수) 크기는 일정합니다. 이것은 여전히 ​​놀라운 구조이므로, 내 컴퓨터에서 크기는 32 바이트입니다 (기본적으로 cv :: Scalar는 double 형식이므로 double은 8 바이트이고 4 * 8 = 32입니다). 그래서 find는 엄격하게 잘못 되었기 때문에 배열의 요소 크기를 32 바이트로 가정하고 3 바이트 여야합니다.

그래서 std :: find와 함께 cv :: Scalar!를 사용하지 마십시오! 그러나 원시 데이터 형식이 훌륭하고 효율적으로 작동합니다.

EDIT2 (berak의 코멘트 후) :

예, 찾기와 이력서 :: Vec3b을 사용할 수 있으며 단순히 올바른 테스트보다 더 많은 테스트를하지 않은 있지만, 그것은 잘 작동 보인다 :

cv::Mat matRGB = cv::Mat(10, 10, CV_8UC3, cv::Scalar(255, 255, 255)); 

std::cout << findValue(matRGB, cv::Vec3b(255, 255, 255)) << std::endl; 
std::cout << findValue(matRGB, cv::Vec3b(255, 255, 254)) << std::endl; 

(여전히 Mat 생성자에서 Scalar를 사용해야하지만 매트는 제대로 초기화됩니다.) 이제 출력은 예상대로입니다 :

1 
0 
+0

당신은'findValue (matRGB, Vec3b (255, 255, 255))'를 시도 했습니까? 스칼라가 ptr <> 템플릿의 잘못된 데이터 유형입니다. – berak

+0

@berak 지금 시도했지만 예상대로 작동합니다. 감사! – marol

관련 문제