티스토리 뷰

영상처리/OpenCV

05. Scanning with iterator

빠리빵 2019. 4. 15. 21:23

이전 포스트에서는 Mat class의 data를 pointer를 사용하여 scanning하는 것을 다루었다. 이번에는 iterator를 사용하여 진행해보도록 한다. 예제는 이전과 같이 color reduction을 진행하고, scanning 방식만 변경하도록 한다.

 

코드와 결과를 먼저 보면 다음과 같다.

#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>

using namespace std;
using namespace cv;

void colorReduction(Mat image, int div = 64) {
	// div must be a power of 2
	int n = static_cast<int>(
		log(static_cast<double>(div)) / log(2.0) + 0.5);
	// mask used to round the pixel value
	uchar mask = 0xFF << n;	// e.g. for div = 16, mask = 0xF0
	uchar div2 = div >> 1;	// div2 = div/2

	// get iterators
	Mat_<Vec3b>::iterator it = image.begin<Vec3b>();
	Mat_<Vec3b>::iterator itend = image.end<Vec3b>();

	// scan all pixels
	for (; it != itend; ++it) {
		(*it)[0] &= mask;
		(*it)[0] += div2;
		(*it)[1] &= mask;
		(*it)[1] += div2;
		(*it)[2] &= mask;
		(*it)[2] += div2;
	}
}

int main() {
	Mat lena = imread("lena.tif", IMREAD_COLOR);
	namedWindow("original");
	namedWindow("after");

	imshow("original", lena);
	colorReduction(lena, 64);
	imshow("after", lena);
	waitKey(0);
}

 

iterator class는 STL(standard template library)에도 존재하며, openCV에서는 C++ STL에 대응되는 cv::Mat iterator class를 제공한다. iterator를 사용하면 얻는 장점은 element type마다 코드가 달라진 필요가 없다는 점이며, 내부의 동작 방식을 노출시키지 않기 때문에 더욱 safe한 코드를 작성할 수 있다는 점이다.

 

Iteration은 image elements에 접근하기 위해 사용되기 때문에, return type은 compilation time에 알아야하며, template 형식으로 사용한다. color image의 경우 다음과 같이 사용할 수 있다.

cv::MatIterator_<cv::Vec3b> it;

Mat_ template class를 사용한다면 다음과 같이 변형할 수 있다.

cv::Mat_<cv::Vec3b>::iterator it;

beginend iterator를 사용하면 pixel을 loop하는 것이 가능하며, color reduction을 다시 작성하면 위의 코드와 같다. 

 

iteration을 사용하는 패턴을 정리하면 다음과 같다. 

1. 영상에 맞는 적절한 iterator object를 생성한다. (위의 예로, color 이미지인 경우 cv::Mat_<cv::Vec3b>::iterator를 사용함)

 

2. starting position의 초기화된 iterator를 얻는다. (위의 예로, 이미지의 upper-left corner) 이것은 begin method를 사용한다. color image라면 image.begin<cv::Vec3b>()로 얻을 수 있다. 

iterator는 산수연산이 가능하며, 예로 이미지의 2행부터 시작하고 싶다면 image.begin<cv::Vec3b>() + image.cols 방식으로 초기화할 수 있다.

 

3. end position은 end method를 이용해서 구할 수 있다. 비슷하게 마지막 row 전에 멈추고 싶다면 final iteration은 image.end<cv::Vec3b>() - image.cols에 닿았을 때 멈추면 된다.

 

4. iterator를 초기화했다면, 다음과 같은 방식으로 loop를 구성할 수 있다.

while (it != itend){
	// process each pixel
    ...
    // end of pixel processing
    ++it;
}

++ 연산자는 다음 element로 이동하는 것에 사용된다. 또한 더 큰 step size를 명시할 수 있으며, 예로 it += 10은 10 pixel마다 처리한다.

 

5. loop 안에서 dereferencing operator *을 사용하여 현재 element value에 접근할 수 있다. 만약 read를 한다면, element = *it; 으로 처리할 수 있다. write의 경우 *it = element;로 처리할 수 있을 것이다. 이 외에도 constant iterator를 사용하여 loop 내에서 Mat instance를 수정하지 않게 하는 것도 가능하다. (cv::MatConstIterator_<cv::Vec3b> it;)

'영상처리 > OpenCV' 카테고리의 다른 글

07. mean / gaussian filter  (1) 2019.04.18
06. Writing efficient scanning loops  (0) 2019.04.16
04.Scanning with pointer  (0) 2019.04.10
03. Accessing pixel values  (0) 2019.04.07
02. Mat 클래스 structure  (0) 2019.04.01
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함