open-cv 영상처리

opencv spread salt

hojung 2021. 6. 18.
728x90
반응형

 

 

 


1. opencv를 이용해서 픽셀 단위에 접근하기

 

opencv에서 이미지 및 영상은 Mat이라는 클래스 안에 담기게 된다. 이 이미지들이나 영상들은 컴퓨터 화면의 하나의 픽셀들로 이루어지는데 opencv 라이브러리를 사용하여 이미지나 영상의 픽셀 하나하나에 접근하여 조작을 할 수 가 있다.

이 떄 사용되는 opencv키워드가 at이다.

at 키워드를 사용하면 이미지나 영상의 픽셀 하나하나에 접근이 가능하다.

이미지의 픽셀에 접근하기 위해서는 이미지나 영상이 가지고 있는 특성을 알아야한다.

이미지는 일단 흑백과 컬러로 구분할 수 있다.

이 때 흑백은 그저 검정색과 흰색의 밝기 차이로서 내부에서의 형태를 구분하지만 컬러 사진인 경우 파란색 채널과 초록색 채널 빨간색 채널 순으로 색들을 합성하여 컬러 사진을 보여주는 것이다.

따라서 우리가 at 키워드를 통해 이미지에 접근하기 위해서는 이 이미지가 흑백, 즉 밝기 조절만하는 채널만을 가지고 있는지 아니면 파란색, 초록색, 빨간색 채널을 모두 가지고 있는지를 구분해 주어야한다.

(물론 보기에는 흑백 사진이라도 세 개의 채널을 모두 가지고 있을 수도 있다. ) 검정색과 회색도 결국 BGR의 합성색이기 떄문이다.

 

opencv에서 흑백 사진임을 알려주는 키워드는 <uchar>이다. 밝기의 조절만이 있을 뿐이므로 흑백 사진에 존재하는 채널은 <uchar>하나 뿐이다.

opencv에서 컬러 사진임을 알려주는 키워드는 <VEC3b>d이다. 이 때 <VEC3b>는 3개의 채널을 가지므로 배열 형태로서 접근할 수 있다.

 

<VEC3b>(row, col)[0] 은 Blue channel

<VEC3b>(row, col)[1] 은 Green channel

<VEC3b>(row, col)[0] 은 Red channel

B->G->R 순으로 구성된다.


2. 적용해보기

그래서 지금부터 난 이미지 픽셀 하나 하나에 접근해서 픽셀 단위를 다루어 보는 test를 할 것이다.

해 볼 test는 opencv를 처음 접해보면 거의 교과서적으로 하는 salt noise를 만드는 문제이다.

마치 이 사진과 같이 소금을 뿌린듯이 노이즈를 생성해보는 것이다.

나는 원본 사진을

사용할 사진

 

이 사진을 사용할 것이다. 이 사진은 흑백으로 보이지만 처음 이미지를 불러오는 imread함수를 사용할 때 flags를 1로 주게 된다면 이미지 내 3개의 채널이 형성된다. 다음은 파란색 초록색 빨간색 노이즈를 무작위로 생성하는 코드를 작성해 보겠다.

void SpreadSalts_blue(Mat img, int num)

{
	//num: 점을 찍을 개수
	for (int n = 0; n < num; n++)
	{
		int x = rand() % img.cols;//img.cols는 이미지의 폭 정보를 저장
		int y = rand() % img.rows; // img.rows는 이미지의 높이 정보를 저장
		//나머지는 나누는 수를 넘을 수 없으므로 무작위 위치가 
		//이미지의 크기를 벗어나지 않도록 제한하는 역할을 하여줌
		
		if (img.channels() == 1)
		{
			//img.channels()는 이미지의 채널 수를 반환
			img.at<uchar>(y, x) = 255;

		}
		else
		{
			img.at<Vec3b>(y, x)[0] = 255; // Blue 채널 접근
			img.at<Vec3b>(y, x)[1] = 0; // Green 채널 접근
			img.at<Vec3b>(y, x)[2] = 0; // Red 채널 접근
		}
	}
}
void SpreadSalts_green(Mat img, int num)

{
	//num: 점을 찍을 개수
	for (int n = 0; n < num; n++)
	{
		int x = rand() % img.cols;//img.cols는 이미지의 폭 정보를 저장
		int y = rand() % img.rows; // img.rows는 이미지의 높이 정보를 저장
		//나머지는 나누는 수를 넘을 수 없으므로 무작위 위치가 
		//이미지의 크기를 벗어나지 않도록 제한하는 역할을 하여줌

		if (img.channels() == 1)
		{
			//img.channels()는 이미지의 채널 수를 반환
			img.at<uchar>(y, x) = 255;

		}
		else
		{
			img.at<Vec3b>(y, x)[0] = 0; // Blue 채널 접근
			img.at<Vec3b>(y, x)[1] = 255; // Green 채널 접근
			img.at<Vec3b>(y, x)[2] = 0; // Red 채널 접근
		}
	}
}
void SpreadSalts_red(Mat img, int num)

{
	//num: 점을 찍을 개수
	for (int n = 0; n < num; n++)
	{
		int x = rand() % img.cols;//img.cols는 이미지의 폭 정보를 저장
		int y = rand() % img.rows; // img.rows는 이미지의 높이 정보를 저장
		//나머지는 나누는 수를 넘을 수 없으므로 무작위 위치가 
		//이미지의 크기를 벗어나지 않도록 제한하는 역할을 하여줌

		if (img.channels() == 1)
		{
			//img.channels()는 이미지의 채널 수를 반환
			img.at<uchar>(y, x) = 255;

		}
		else
		{
			img.at<Vec3b>(y, x)[0] = 0; // Blue 채널 접근
			img.at<Vec3b>(y, x)[1] = 0; // Green 채널 접근
			img.at<Vec3b>(y, x)[2] = 255; // Red 채널 접근
		}
	}
}

 

3개의 함수 모두 기본적인 틀은 같으나 채널 접근 기준만 달라진다. 또한 무작위로 점을 찍기 때문에 rand함수를 사용해서 랜덤한 자리에 점이 찍히도록 하였다.

 

함수의 내용은 at키워드를 통해 각각의 채널 픽셀에 접근한 후 값을 설정해주는 것이다.

다음과 같은 함수의 실행 결과는 아래와 같다.

 

파란색, 초록색, 빨간색 점들이 잘 생성되었다.

 

728x90
반응형

'open-cv 영상처리' 카테고리의 다른 글

opencv C++ BandPass Filter  (2) 2022.03.24
opencv c++ sobel filter  (0) 2022.03.23
opencv c++ 가우시안 필터  (0) 2022.03.23
opencv 사진 합성  (0) 2021.06.18

댓글