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