디지털 영상처리 - 부분 Mosaic

ImageProcessing

Posted by kwon on 2019-12-01

논리 연산

영상을 처리하기 위하여 단순하게 수를 더하거나 빼는 연산만을 수행하는 것이 아니라 영상에 대하여 논리적인 연산을 수행하여 원하는 결과를 얻을 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Circle(uchar** Result, int Row, int Col, double diameter) // 원하는 반지름의 크기로 원 생성
{
int i, j;
double tmp, xSquare, ySquare;

for(i=0;i<Row;i++)
for (j = 0; j < Col; j++)
{
ySquare = (abs(Row / 2 - i)) * (abs(Row / 2 - i)); // (Row/2, Col/2) 는 중심의 좌표
xSquare = (abs(Col / 2 - j)) * (abs(Col / 2 - j));

tmp = sqrt(ySquare + xSquare); // tmp는 현재 위치의 중심과의 거리 - 피타고라스 정리 x^2 + y^2 = z^2
//sqrt() : 제곱근을 구하는 함수
if (tmp < diameter) Result[i][j] = 255; //
else Result[i][j] = 0;
}
}

위의 코드는 반지름의 길이를 매개변수로 받아 원하는 반지름을 가지는 원을 생성해주는 함수이다. 중심과의 거리를 이용하여 반지름보다 큰 범위의 값은 모두 0으로 작은 값은 모두 255로 변환하게 된다.

위의 이미지는 반지름이 100인 circle image이다. 다음은 두 이미지를 인자로 받아 and 연산과 or 연산을 수행해주는 함수이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

void MaskOr(uchar** in1Img, uchar** in2Img, uchar** outImg, int Row, int Col) // or 연산
{
int i, j;

for (i = 0; i < Row; i++)
for (j = 0; j < Col; j++) {
outImg[i][j] = in1Img[i][j] | in2Img[i][j];
}
}
void MaskAnd(uchar** in1Img, uchar** in2Img, uchar** outImg, int Row, int Col) // and 연산
{
int i, j;

for (i = 0; i < Row; i++)
for (j = 0; j < Col; j++) {
outImg[i][j] = in1Img[i][j] & in2Img[i][j];
}
}

위의 함수들을 이용하여 lena영상의 얼굴 부분만을 구할 수 있다.

위의 이미지는 lena와 circle을 AND연산을 수행하여 얻은 결과이다.(diameter=150)
위의 이미지는 lena와 circle을 OR연산을 수행하여 얻은 결과이다.

이를 응용하면 원하는 부분만 모자이크 처리를 수행하는 것이 가능하다. 먼저 lena와 circle이미지를 OR연산을 수행한 뒤 앞서 해보았던 mosaic 함수를 이용하여 모자이크된 lena영상과 AND연산을 수행하면 된다. 하지만 위와 같은 방법을 사용하면 메모리를 여러 개 할당해야하는 불편함과 위치를 원하는 곳으로 지정할 수 없는 불편함 있기 때문에 다음과 같은 함수를 작성하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void CircleMosaic(uchar** img, uchar** outimg, int Row, int Col, int x, int y, double diameter, int block)
{
int i, j, a, b;
double tmp, xSquare, ySquare, avg = 0;
int mtmp, count;

mosaic(img, outimg, Row, Col, block); // outimg에 모자이크된 이미지 저장

for(i = 0; i < Row; i++)
for (j = 0; j < Col; j++)
{
ySquare = (y - j) * (y - j);
xSquare = (x - i) * (x - i);

tmp = sqrt(ySquare + xSquare); // 피타고라스 정리 -> 중심과의 거리 찾기

if (tmp < diameter) outimg[i][j]; // 현재 픽셀의 위치가 입력받은 반지름보다 작으면 모자이크된 이미지를 유지
else outimg[i][j] = img[i][j]; // 그렇지 않으면 원본이미지를 대입
}

}

위의 함수는 원하는 좌표와 반지름을 매개변수로 받아 해당하는 위치에 모자이크 처리를 수행하는 함수이다. mosaic함수는이전 포스팅에서 사용했던 함수이고 circle이미지를 제작할 때 사용했던 방식으로 작성하였다. 위의 함수를 이용하면 다음과 같은 이미지도 출력이 가능하다.

부분 모자이크(300,350) (diameter=100, block=8) ## 응용

이번엔 원형이 아닌 사각형 이미지를 생성하는 함수와 그 함수를 응용하여 사각형으로 부분 모자이크를 수행하는 함수이다.

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
32
void Square(uchar** Result, int Row, int Col, double diameter) // 사각형 이미지 생성
{
int i, j;
double tmp;
diameter = diameter / 2; // 사각형의 한변의 길이를 입력받았으므로 1/2 해줌

for(i = 0; i < Row; i++)
for (j = 0; j < Col; j++)
{
if (i >= (Row / 2) - diameter && i <= (Row / 2) + diameter && j >= (Col / 2) - diameter && j <= (Col / 2) + diameter)
Result[i][j] = 255;
else Result[i][j] = 0;
}

}

void SquareMosaic(uchar** img, uchar** outimg, int Row, int Col, int x, int y, int diameter, int block) // 사각형 부분 모자이크
{
int i, j;
diameter = diameter / 2; // 사각형의 한 변의 길이를 입력받았으므로 1/2 해줌

mosaic(img, outimg, Row, Col, block);

for(i = 0; i < Row; i++)
for (j = 0; j < Col; j++)
{
if (i >= x - diameter && i <= x + diameter && j >= y - diameter && j <= y + diameter) // 사각형 범위 지정
outimg[i][j]; // 사각형 내부는 모자이크 이미지 유지
else outimg[i][j] = img[i][j]; // 사각형 외부를 원본 대입
}

}

사각형의 한 변의 길이를 입력받아 사각형 이미지 및 사각형 부분 모자이크를 수행하며 결과는 다음과 같다.

Square Image (diameter=200)
사각형 부분 모자이크(300,300) (diameter=150, block=8)

위와 같이 사각형 모양으로도 부분 모자이크를 구현할 수 있다. 영상처리에서 논리 연산은 원하는 영상의 모양을 얻거나 제거하기 위한 기법으로 사용되며 얼굴에서 치아나 눈 등 특별히 보고 싶은 부분이 있다면 특정한 영상을 이용하여 원하는 결과 영상을 얻을 수 있다.