-
CS50 Week4: Problem Set, FiltersProgramming/CS50 2023. 7. 14. 20:53
하버드 CS50 강의 4주차 Poblem Set 과제 Filters 의 풀이 과정을 다룹니다.
C언어로 이차원 배열으로 표현된 이미지를 다루는 문제입니다.Intro
문제 링크에서 자세한 내용을 확인할 수 있습니다.
다양한 이미지 필터를 만드는 문제
$ ./filter -r IMAGE.bmp REFLECTED.bmp
Code
다음 4가지 함수를 구현해야한다.
grayscale
: 이미지를 흑백으로 변환reflect
: 이미지를 좌우 반전blur
: 이미지를 흐리게 만듬edges
: 이미지의 가장자리를 강조
grayscale 함수
RGB 값의 평균을 구해서 때려박는다.
// Convert image to grayscale void grayscale(int height, int width, RGBTRIPLE image[height][width]) { for (int i = 0; i < height; i++) { for (int j = 0; j < height; j++) { int avg_brightness = round((image[i][j].rgbtBlue + image[i][j].rgbtGreen + image[i][j].rgbtRed) / 3.0); // Set all colors to the average brightness, thus making the image grayscale image[i][j].rgbtBlue = avg_brightness; image[i][j].rgbtGreen = avg_brightness; image[i][j].rgbtRed = avg_brightness; } } return; }
reflect 함수
절반을 기준으로 대응되는 값을 서로 바꾸어준다.
홀수여도 괜찮다. 중간은 무시하면 된다.// Reflect image horizontally void reflect(int height, int width, RGBTRIPLE image[height][width]) { for (int i = 0; i < height; i++) { for (int j = 0; j < (width / 2); j++) { // Swap corresponding pixels from left and right sides of the image RGBTRIPLE temp = image[i][j]; image[i][j] = image[i][width - j - 1]; image[i][width - j - 1] = temp; } } return; }
blur 함수
각 픽셀을 기준으로
di
,dj
를 두어서 주변 픽셀을 순회하며 평균을 계산한다.
바깥으로 벗어나는 경우를 주의해한다.continue
를 사용해서 처리해주기로 한다.blur
함수는 주변 픽셀 값을 참조해서 평균을 계산한다.처리 해서 바꾼 픽셀을 input 이미지에 그대로 넣어버리면 다음 계산에 영향이 갈 수 있다.
따라서 같은 크기의 배열temp_image
를 만들어서 계산이 다 끝난 이후에야 원본 이미지를 바꿔준다.// Blur image void blur(int height, int width, RGBTRIPLE image[height][width]) { RGBTRIPLE temp_image[height][width]; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { // Calculate color average of the 3x3 grid surrounding image[i][j] pixel int sum_red = 0; int sum_green = 0; int sum_blue = 0; int pixels_count = 0; for (int di = -1; di <= 1; di++) { for (int dj = -1; dj <= 1; dj++) { if (i + di < 0 || i + di >= height || // Height out of bound j + dj < 0 || j + dj >= width) // Width out of bound { continue; } sum_red += image[i + di][j + dj].rgbtRed; sum_green += image[i + di][j + dj].rgbtGreen; sum_blue += image[i + di][j + dj].rgbtBlue; pixels_count++; } } temp_image[i][j].rgbtRed = round((float) sum_red / pixels_count); temp_image[i][j].rgbtGreen = round((float) sum_green / pixels_count); temp_image[i][j].rgbtBlue = round((float) sum_blue / pixels_count); } } // Copy temp_image to image for (int j = 0; j < width; j++) { for (int i = 0; i < height; i++) { image[i][j] = temp_image[i][j]; } } return; }
edges 함수
복잡해 보이지만 지금까지 한 내용을 토대로 명세에 맞추어 구현하기만 하면 된다.
// Detect edges void edges(int height, int width, RGBTRIPLE image[height][width]) { RGBTRIPLE temp_image[height][width]; // Sobel operator kernels int Gx_kernel[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}}; int Gy_kernel[3][3] = {{-1, -2, -1}, { 0, 0, 0}, { 1, 2, 1}}; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int Gx_red = 0; int Gx_green = 0; int Gx_blue = 0; int Gy_red = 0; int Gy_green = 0; int Gy_blue = 0; // Calculate gradient for each color, using 3x3 Sobel operator kernels for (int di = -1; di <= 1; di++) { for (int dj = -1; dj <= 1; dj++) { if (i + di < 0 || i + di >= height || // Height out of bound j + dj < 0 || j + dj >= width) // Width out of bound { // Out of bound pixels are considered to be black(0x00 for each RGB) continue; } else { Gx_red += image[i + di][j + dj].rgbtRed * Gx_kernel[di + 1][dj + 1]; Gx_green += image[i + di][j + dj].rgbtGreen * Gx_kernel[di + 1][dj + 1]; Gx_blue += image[i + di][j + dj].rgbtBlue * Gx_kernel[di + 1][dj + 1]; Gy_red += image[i + di][j + dj].rgbtRed * Gy_kernel[di + 1][dj + 1]; Gy_green += image[i + di][j + dj].rgbtGreen * Gy_kernel[di + 1][dj + 1]; Gy_blue += image[i + di][j + dj].rgbtBlue * Gy_kernel[di + 1][dj + 1]; } } } // Calculate gradient magnitude, cap at 255 temp_image[i][j].rgbtRed = fmin(round(sqrt(Gx_red * Gx_red + Gy_red * Gy_red)), 255); temp_image[i][j].rgbtBlue = fmin(round(sqrt(Gx_blue * Gx_blue + Gy_blue * Gy_blue)), 255); temp_image[i][j].rgbtGreen = fmin(round(sqrt(Gx_green * Gx_green + Gy_green * Gy_green)), 255); } } // Copy temp_image to image for (int j = 0; j < width; j++) { for (int i = 0; i < height; i++) { image[i][j] = temp_image[i][j]; } } return; }