2012년 12월 28일 금요일

OpenCV #2-1 Example (화소값에 접근)

OpenCV #2 화소 다루기

  • Example (Salt-and-pepper noise)

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

void salt(cv::Mat &image, int n){ 
// &image는 읽어들인 이미지
//n은 흰색 값으로 덮기 원하는 화소의 개수
for(int k=0 ; k<n ; k++){
int i = rand()%image.cols; // rand()는 MFC 난수 생성기
int j = rand()%image.rows; // cols와 rows로 나눈 나머지 수 사용

if(image.channels() == 1){ // 그레이레벨 영상
image.at<uchar>(j, i) = 255; // 255는 흰색. j, i를 흰색으로 바꿈.
}
else if(image.channels() == 3){ // 컬러 영상
image.at<cv::Vec3b>(j, i)[0] = 255;
image.at<cv::Vec3b>(j, i)[1] = 255;
image.at<cv::Vec3b>(j, i)[2] = 255;
}
}
}

int main()
{
srand(cv::getTickCount()); // 임의 숫자 생성기 초기화

cv::Mat image = cv::imread("boldt.jpg");
// cv::Mat image = cv::imread("boldt.jpg", 0); // 0이 들어가면 회색조

salt(image, 3000);

cv::namedWindow("Image");
cv::imshow("Image", image);
cv::imwrite("slated.bmp", image);
cv::waitKey(5000);

return 0;
}


  • Result



  • 예제 분석

 - public 멤버 변수인 cols와 rows는 영상의 행과 열

 - 각 원소에 접근 하려면 cv::Mat의 at(int x, int y) 메소드를 이용
 - cv::Mat은 임의 타입의 요소를 갖지만 반환 타입을 지정해야 한다.
 - at 메소드를 호출하면 영상 원소 타입을 image.at<uchar>(j, i)=255;로 지정해야 한다.

 - 특정 타입을 행렬 내 타입과 일치하는지 반드시 확인해야 한다.
 - at 메소드는 모든 종류의 타입 변환을 수행하지 않는다.
 - 컬러 영상을 갖는 cv::Mat는 세 8비트 값의 벡터를 반환한다.
 - OpenCV는 byte 백터인 cv::Vec3b 같은 정의된 타입을 제공한다.
 - cv::Vec3b는 세 개의 unsigned char인 벡터다.
 - image.at<cv::Vec3b>(j ,i)[channel] = value; // channel은 세 개 컬러 채널 중 하나
 - Vec3b의 b는 byte를 의미하고, short의 s, int의 i, float의 f, double의 d가 있다.
 - 템플릿 클래스 cv::Vec<T, N>에서 T는 타입, N은 백터 요소의 개수

  • 부연 설명

 - 행렬 타입을 알고 있다면 cv::Mat의 템플릿 하위 클래스인 cv::Mat_클래스를 사용할 수 있다.
 - 이 클래스는 새로운 데이터 속성이 없기 때문에 포인터나 참조자로 해당 클래스를 다른 클래스로 직접 변환한다.
 - 그러므로 image가 uchar 행렬을 참조하고 있다면 다음과 같이 쓴다.
 - cv::Mat_<uchar> im2 = image; // im2는 image를 참조
 - im2(50, 100) = 0; // 50번째 행, 100번째 열, 즉 (50, 100)에 있는 화소에 접근
 - 즉, cv::Mat_의 원소 타입은 변수를 만들 때 선언된다.


  • 참고문헌 : OpenCV 2 Computer Vision Application Programming Cookbook