본문 바로가기
IT

[openCV / C++ ] 픽셀 아트 만들기

by 배애앰이 좋아 2020. 12. 31.
반응형

오늘은 그림을 아래와 같이 바꾸는 방법에 대해 소개해볼까 합니다.

 

왼쪽 원본 오른쪽 만든 픽셀 아트

 

아래 코드는 pixel 함수로 symbol[4] 배열에 총 4가지의 기호로 그림을 표현주었다. (아스크 코드 번호 참조)

또한, 그림에 기호를 넣기 위해 아래와 같이 설정을 해주었다.

CvFont font;
cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 1.0, 1.0);

현재 mask는 10x10으로 설정하였으며 해당 밝기 값을 다 더해서 /100(mask*mask size) /255(RGB 값) 나누기를 하면 최종적으로 0 ~ 1 사이 값이 나오게 된다. 이때 0~1 사이를 4 범위로 나눠주어서 (4개의 기호로 표현해주기 때문에) cvPutText(cpimg, text, cvPoint(i,j), &font, CV_RGB(0, 0, 0)); 에 넣어준다.

 

void pixel(IplImage *img, IplImage *cpimg)
{
	int mask = 10;
	char symbol[4] = {35, 47, 42, 46};
	CvFont font;
	cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 1.0, 1.0);
	for (int i = 0; i < img->width-mask; i += mask)
	{
		for (int j = 0; j < img->height - mask; j += mask)
		{
			double bright = 0.0;
			for (int mx = i; mx < i + mask; mx++)
			{
				for (int my = j; my< j + mask; my++)
				{
					auto c = cvGet2D(img, my, mx);
					bright += (c.val[0] + c.val[1] + c.val[2]) / 3.0;
				}
			}
			bright /= (mask*mask); //0~255
			int index = (int)((bright / 255.0) * 4);
			char text[2] = { symbol[index], NULL };
			cvPutText(cpimg, text, cvPoint(i,j), &font, CV_RGB(0, 0, 0));
		}
	}
}

 

아래 코드는 다른 openCV 관련 글에서도 계속 써듯이 원본 이미지와 바뀐 이미지를 붙여서 비교하기 위한 함수이다. 원본 이미지의 width 값을 2배하여서 한쪽에는 원본 이미지 픽셀을 복사 다른 한 쪽에는 바뀐 이미지 픽셀을 복사하여 한 window 창에 보여줄 수 있게 한다.

 

IplImage *merge(IplImage *img, IplImage *cpimg)
{
	IplImage *bimg = cvCreateImage(cvSize(img->width * 2, img->height), 8, 3);
	for (int i = 0; i < img->width; i++)
	{
		for (int j = 0; j < img->height; j++)
		{
			auto color1 = cvGet2D(img, j, i);
			auto color2 = cvGet2D(cpimg, j, i);
			cvSet2D(bimg, j, i, color1);
			cvSet2D(bimg, j, img->width + i, color2);
		}
	}
	return bimg;
}

 

위에 함수들을 호출하는 main이다.

 

int main(void)
{
	IplImage *img = cvLoadImage("img//cat3.jpg");
	IplImage *cpimg = cvCreateImage(cvGetSize(img), 8, 3);
	
	cvSet(cpimg, CV_RGB(255, 255, 255)); //배경 흰색으로 바꿔주기
	pixel(img, cpimg);
	
	auto bimg = merge(img, cpimg);
	cvShowImage("My Window", bimg);

	cvWaitKey();
	cvDestroyAllWindows();
	cvReleaseImage(&img);
}

 

아래는 풀 코드이다.

 

#include <stdio.h>
#include "opencv2/opencv.hpp"

void pixel(IplImage *img, IplImage *cpimg)
{
	int mask = 10;
	char symbol[4] = {35, 47, 42, 46};
	CvFont font;
	cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 1.0, 1.0);
	for (int i = 0; i < img->width-mask; i += mask)
	{
		for (int j = 0; j < img->height - mask; j += mask)
		{
			double bright = 0.0;
			for (int mx = i; mx < i + mask; mx++)
			{
				for (int my = j; my< j + mask; my++)
				{
					auto c = cvGet2D(img, my, mx);
					bright += (c.val[0] + c.val[1] + c.val[2]) / 3.0;
				}
			}
			bright /= (mask*mask); //0~255
			int index = (int)((bright / 255.0) * 4);
			char text[2] = { symbol[index], NULL };
			cvPutText(cpimg, text, cvPoint(i,j), &font, CV_RGB(0, 0, 0));
		}
	}
}

IplImage *merge(IplImage *img, IplImage *cpimg)
{
	IplImage *bimg = cvCreateImage(cvSize(img->width * 2, img->height), 8, 3);
	for (int i = 0; i < img->width; i++)
	{
		for (int j = 0; j < img->height; j++)
		{
			auto color1 = cvGet2D(img, j, i);
			auto color2 = cvGet2D(cpimg, j, i);
			cvSet2D(bimg, j, i, color1);
			cvSet2D(bimg, j, img->width + i, color2);
		}
	}
	return bimg;
}

int main(void)
{
	IplImage *img = cvLoadImage("img//cat3.jpg");
	IplImage *cpimg = cvCreateImage(cvGetSize(img), 8, 3);
	
	cvSet(cpimg, CV_RGB(255, 255, 255)); //배경 흰색으로 바꿔주기
	pixel(img, cpimg);
	
	auto bimg = merge(img, cpimg);
	cvShowImage("My Window", bimg);

	cvWaitKey();
	cvDestroyAllWindows();
	cvReleaseImage(&img);
}

 

 

그 밖에 결과 이미지들 : 

 

결과 이미지 2

 

결과 이미지 2

 

결과가 귀엽게 잘 나온 것을 확인할 수 있습니다. 다음 글에는 또 다른 새로운 것을 시도해보겠습니다.

문득 이 프로젝트를 하니 이미지를 도트화 시켜 보는 프로젝트도 해보고 싶네요 기회가 되면 다음 번에 시도해서 글을 작성해보겠습니다.

반응형

댓글