OpenCV 학습 노트(10):MAT 대상의 데이터를 보는 세 가지 방법

64764 단어 OpenCV 학습 노트
Mat의 대상이 생기면 이미지 처리를 시작할 수 있습니다.
이미지를 처리하는 과정에서 데이터를 보고 수정하는 것은 비교적 빈번한 작업이어야 한다.
공식 수첩에서 제시한 세 가지 방법을 말씀드리겠습니다.
첫 번째 방법: Mat 데이터 부분을 가리키는 포인터를 사용합니다.
코드는 다음과 같습니다.
 1 Mat& ScanImageAndReduceC(Mat& I, const uchar* const table)
 2 {
 3     // accept only char type matrices
 4     CV_Assert(I.depth() != sizeof(uchar));
 5 
 6     int channels = I.channels();
 7 
 8     int nRows = I.rows;
 9     int nCols = I.cols * channels;
10 
11     if (I.isContinuous())
12     {
13         nCols *= nRows;
14         nRows = 1;
15     }
16 
17     int i,j;
18     uchar* p;
19     for( i = 0; i < nRows; ++i)
20     {
21         p = I.ptr(i);
22         for ( j = 0; j < nCols; ++j)
23         {
24             p[j] = table[p[j]];
25         }
26     }
27     return I;
28 }

11 줄은 isContinous 함수를 사용합니다. 그림의 줄마다 연속적이고, 한 줄의 줄 끝과 다음 줄의 시작 데이터 사이의 메모리 단원이 다른 데이터를 저장하지 않도록 하기 위해서입니다.이 함수가true로 되돌아오면, 우리는 그림을 1줄, row*col열의 데이터 형식으로 옮겨다닐 수 있습니다.
21 줄은 ptr 함수를 사용합니다. 0에서 시작하는 줄 번호를 나타내는 매개 변수를 받아들입니다.ptr의 반환값은 기본적으로 uchar* 또는 const uchar* (const 버전의 재부팅) 입니다.또한 ptr는 템플릿이 있어 ptr를 통해 type*와const type*의 반환값을 실현할 수 있다.이 반환 값은 지정한 줄 번호를 가리키는 바늘을 되돌려줍니다.ptr 방법으로 되돌아오는 바늘을 사용합니다. 그림의 모든 바이트 (또는 우리가 지정한 type 길이) 가 픽셀이 아니라, 그림의 모든 바이트 (9행 ncols의 정의에 주의하십시오.)
 
두 번째 방법: 교체기를 사용한다.
코드는 다음과 같습니다.
 1 Mat& ScanImageAndReduceIterator(Mat& I, const uchar* const table)
 2 {
 3     // accept only char type matrices
 4     CV_Assert(I.depth() != sizeof(uchar));
 5 
 6     const int channels = I.channels();
 7     switch(channels)
 8     {
 9     case 1:
10         {
11             MatIterator_ it, end;
12             for( it = I.begin(), end = I.end(); it != end; ++it)
13                 *it = table[*it];
14             break;
15         }
16     case 3:
17         {
18             MatIterator_ it, end;
19             for( it = I.begin(), end = I.end(); it != end; ++it)
20             {
21                 (*it)[0] = table[(*it)[0]];
22                 (*it)[1] = table[(*it)[1]];
23                 (*it)[2] = table[(*it)[2]];
24             }
25         }
26     }
27 
28     return I;
29 }

 
MatIterator_Mat의 교체기입니다. 템플릿도 지원합니다.12행과 19행의 순환에서, 우리는 Mat의 begin과end 함수를 사용하여, 교체기가 각각 Mat 데이터 부분의 시작과 끝을 가리키도록 했다.begin과 end의 실현은 다음과 같다.
 1 template inline MatIterator_<_tp> Mat::begin()
 2 {
 3     CV_DbgAssert( elemSize() == sizeof(_Tp) );
 4     return MatIterator_<_tp>((Mat_<_tp>*)this);
 5 }
 6 
 7 template inline MatIterator_<_tp> Mat::end()
 8 {
 9     CV_DbgAssert( elemSize() == sizeof(_Tp) );
10     MatIterator_<_tp> it((Mat_<_tp>*)this);
11     it += total();
12     return it;
13 }

4행과 10행에 Mat < 가 사용되었음을 알 수 있습니다.tp> 유형, 이것은 Mat가 특정한 유형에 대한 템플릿으로 볼 수 있으며, 깊이 연구하지 않습니다.Mat_<_tp> 형식은 그림의 데이터를 조작하는 데 편리합니다.문서의 간단한 예를 들면 다음과 같습니다.
1 Mat M(100, 100, CV_8U);
2 
3 Mat_<float>& M1 = (Mat_<float>&)M;
4 
5 M1(99, 99) = 1.f

 Mat_형식은 OpenCV 개발자가 괄호 조작부호를 다시 불러왔기 때문에 데이터를 쉽게 조작할 수 있습니다.우리 Mat 보자.유형 3채널 이미지 처리:
1 Mat_ img(240, 320, Vec3b(0, 255, 0));
2 
3 for (int i = 0; i < 100; i++)
4     img(i, i) = Vec3b(255, 255, 255);
5 //  ( ) 
6 for (int i = 0; i < img.rows; i++)
7     for (int j = 0; j < img.cols; j++)
8         img(i, j)[2] ^= (uchar)(i ^ j);

교체기의 조작 중 우리가 가장 자주 사용하는 것은++와 * 조작부호이다. 어떻게 실현되는지 살펴보자.
 1 template inline _Tp& MatIterator_<_tp>::operator *() const { return *(_Tp*)(this->ptr); }
 2 
 3 template inline MatIterator_<_tp> MatIterator_<_tp>::operator ++(int)
 4 {
 5     MatIterator_ b = *this;
 6     MatConstIterator::operator ++();
 7     return b;
 8 }
 9 //  MatIterator_<_tp> MatConstIterator , 
10 inline MatConstIterator MatConstIterator::operator ++(int)
11 {
12     MatConstIterator b = *this;
13     *this += 1;
14     return b;
15 }
16 //  += ,sliceStart sliceEnd   , Mat 
17 inline MatConstIterator& MatConstIterator::operator += (ptrdiff_t ofs)
18 {
19     if( !m || ofs == 0 )
20         return *this;
21     ptrdiff_t ofsb = ofs*elemSize;
22     ptr += ofsb;
23     if( ptr < sliceStart || sliceEnd <= ptr )
24     {
25         ptr -= ofsb;
26         seek(ofs, true);
27     }
28     return *this;
29 }

 
 
세 번째 방법:at방법 또는 Mat 사용유형
at 방법을 사용하면 지정한 데이터를 무작위로 접근할 수 있다.코드는 다음과 같습니다.
 1 Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar* const table)
 2 {
 3     // accept only char type matrices
 4     CV_Assert(I.depth() != sizeof(uchar));
 5 
 6     const int channels = I.channels();
 7     switch(channels)
 8     {
 9     case 1:
10         {
11             for( int i = 0; i < I.rows; ++i)
12                 for( int j = 0; j < I.cols; ++j )
13                     I.at(i,j) = table[I.at(i,j)];
14             break;
15         }
16     case 3:
17         {
18          Mat_ _I = I;
19 
20          for( int i = 0; i < I.rows; ++i)
21             for( int j = 0; j < I.cols; ++j )
22                {
23                    _I(i,j)[0] = table[_I(i,j)[0]];
24                    _I(i,j)[1] = table[_I(i,j)[1]];
25                    _I(i,j)[2] = table[_I(i,j)[2]];
26             }
27          I = _I;
28          break;
29         }
30     }
31 
32     return I;
33 }

 
13줄에서at(i, j)를 사용했습니다. 이 방법은 i줄 j열의 데이터를 인용합니다.at 방법은 cv::Point 형식의 매개 변수를 전송할 수 있습니다. 예를 들어at (cv:Point2f (16,18).
우리는 18행에 Mat 를 사용했음을 알아차렸다.위에서 말한 바와 같이 템플릿과 무작위 접근을 지원하는 Mat류의 변형으로 볼 수 있다.Mat_임의 액세스를 지원하기 위해 괄호 연산자가 다시 로드되고 코드는 다음과 같습니다.
1 template inline const _Tp& Mat_<_tp>::operator ()(int i0, int i1) const
2 {
3     CV_DbgAssert( dims <= 2 && data &&
4                   (unsigned)i0 < (unsigned)size.p[0] &&
5                   (unsigned)i1 < (unsigned)size.p[1] &&
6                   type() == DataType<_tp>::type );
7     return ((const _Tp*)(data + step.p[0]*i0))[i1];
8 }

다음으로 이동:http://www.cnphp6.com/archives/61006?utm_source=tuicool

좋은 웹페이지 즐겨찾기