개발자 블로그
영상처리 강좌 - 5. 이미지 밝기를 조절해보자! 본문
오늘 배워볼 내용은 이미지의 밝기를 조절하는 것 입니다. 이미지의 밝기를 밝게도 해보고 어둡게도 해보고 또 색을 반전하는 것 까지 한번 공부해보도록 하겠습니다.
☞ 2015/08/10 - [영상처리강좌] - 영상처리 강좌를 시작합니다~!!
우리는 이미 이전 강의를 통해서 살짝이나마 이미지를 밝게 하는 법에 대해서 배웠습니다. Gray 영상은 픽셀값이 0 ~ 255로 이루어져 있으며, 아래와 같은 색상체계를 가지고 있습니다. 즉, 0은 검정색, 255는 흰색입니다.
뭐, 이정도야 포토샵 몇 번 써보셨다면 다 알고 계실 것 입니다.(RGB역시 비슷한 구조이고요.)
결국 영상의 밝기를 밝게 한다는 것은 픽셀의 값을 255에 근접하게 하는 것이고, 영상을 어둡게 만드는 것은 이와 반대로 0에 가깝도록 값을 조절해주면 되는 것 입니다.
그렇다면 왜 255인가? 그건 1Byte(8bit)로 표현할 수 있는 최대의 숫자가 255이기 때문입니다.(2^8 = 256 이고, 따라서 0 ~ 255 까지의 범위를 갖습니다.)
영상의 밝기를 변경할 때 주의할 한가지는 픽셀값이 0 과 255 사이를 벗어나지 않도록 하는것 입니다. 저 범위를 넘어서는 값을 넣을 때는 어떤 결과가 나올지는 한번 실습을 통해서 확인해 보도록 하겠습니다.
자, 그럼 먼저 영상을 밝게 하는 함수입니다.
int fnWritePGM(char* fileNm, PGMImage* img) { FILE* fp; fp = fopen(fileNm, "w"); if(fp == NULL){ fprintf(stderr, "파일 생성에 실패하였습니다.\n"); return FALSE; } fprintf(fp, "%c%c\n", 'P', '2'); fprintf(fp, "%d %d\n" , img->width, img->height); fprintf(fp, "%d\n", 255); int tmp; // int type임에 유의 for(int i=0; i<img->height; i++){ for(int j=0; j<img->width; j++){ tmp = img->pixels[i][j] + 40; // 픽셀값을 밝게 변화를 줌 if(tmp > 255){ // overflow 방지 tmp = 255; } fprintf(fp, "%d ", tmp); } } fclose(fp); return TRUE; }
"픽셀값을 밝게 변화를 줌", "overflow 방지" 라고 주석 달아놓은 부분이 전부 입니다. 이중 for 문으로 이미지 전체 픽셀에 하나하나 접근하면서 픽셀의 값을 일괄적으로 +40해서 저장합니다. 그 밑은 overflow를 방지하기 위한 코드이고요.
영상을 어둡게 하는 것은 +40에서 부호만 바꿔주면 됩니다. 값이야 뭐 당연히 여러분들이 적당한 값으로 변경해주셔도 되고요~! overflow 방지하는 부분은 이제 255를 넘는지가 아니라 0보다 작은 값을 갖게 되는지 underflow 체크를 해주면 됩니다. 소스는 아래와 같습니다.
int fnWritePGM(char* fileNm, PGMImage* img) { FILE* fp; fp = fopen(fileNm, "w"); if(fp == NULL){ fprintf(stderr, "파일 생성에 실패하였습니다.\n"); return FALSE; } fprintf(fp, "%c%c\n", 'P', '2'); fprintf(fp, "%d %d\n" , img->width, img->height); fprintf(fp, "%d\n", 255); int tmp; // int type임에 유의 for(int i=0; i<img->height; i++){ for(int j=0; j<img->width; j++){ tmp = img->pixels[i][j] - 40; // 픽셀값을 어둡게 변화를 줌 if(tmp < 0){ // underflow 방지 tmp = 0; } fprintf(fp, "%d ", tmp); } } fclose(fp); return TRUE; }
overflow 방지 로직에 대해서 부연설명을 좀 더 하자면, 먼저 밝게 변경하는 경우에, 이미 기존 영상에서 값이 255인 픽셀이 있을 수 있습니다. 그런데 거기에 영상을 밝게 하기위해서 값을 더 더한다면 255를 초과하게 되고, 우리는 원하는 결과를 얻지 못 할 것 입니다. (이 부분은 컴퓨터구조를 공부하시면 자세히 알 수 있습니다. 이 강좌에서 자세히 설명하기는 좀 그렇고,, 그냥 결과만 아래에서 확인해보죠~ㅋ)
어둡게 할 때 역시 마찬가지 입니다. 기존 영상에도 이미 어두운 부분이 있을 것이고, 만약 픽셀값이 예를들어 10이라고 했을 때, -30을 하게 되면 값은 -20이 되어 버립니다. 결국 이러한 부분 때문에 overflow(또는 underflow)를 체크하는 로직이 반드시 필요한 것 입니다.
그럼 각각의 결과를 비교해 보도록 하겠습니다. 먼저 밝게 처리한 영상의 결과 화면입니다. 왼쪽에 있는 사진이 원본사진, 오른쪽에 있는 사진이 밝게 처리한 결과 영상입니다.
다음은 어둡게 처리한 화면입니다.
밝게 또는 어둡게.. 감이 오시나요?? 뭐,, 픽셀값에 +/- 만 해주는게 전부이기 때문에 어려운 부분은 없습니다.
그럼 조금 더 응용을 해보겠습니다. 요즘은 디카가 많아서 필름카메라를 많이 쓰지 않지만, 예전 필름카메라의 필름을 보면 색이 거꾸로 되어있죠(네거티브 필름이라고 하나요?). 이러한 효과(색반전, invert)를 한번 줘 보도록 하겠습니다.
int fnWritePGM(char* fileNm, PGMImage* img) { FILE* fp; fp = fopen(fileNm, "w"); if(fp == NULL){ fprintf(stderr, "파일 생성에 실패하였습니다.\n"); return FALSE; } fprintf(fp, "%c%c\n", 'P', '2'); fprintf(fp, "%d %d\n" , img->width, img->height); fprintf(fp, "%d\n", 255); unsigned char tmp; for(int i=0; i<img->height; i++){ for(int j=0; j<img->width; j++){ tmp = 255 - img->pixels[i][j]; // 픽셀값 색 반전 fprintf(fp, "%d ", tmp); } } fclose(fp); return TRUE; }
프로그램의 실행 결과는 아래와 같습니다.
이제 마지막으로 밝은 부분은 더 밝게, 어두운 부분은 더 어둡게 하는 처리를 해보겠습니다.(이게 포토샵에서 스크린 효과인가요?? 이름이 있을텐데,, 잘 모르겠네요..-_-;; 그냥 고대비효과 라고 해야하나..?) 암튼~ 이런 처리를 하면 사진이 뭔가 좀 더 느낌있어 보입니다. (그냥 제 주관적인 생각입니다..^^)
int fnWritePGM(char* fileNm, PGMImage* img) { FILE* fp; fp = fopen(fileNm, "w"); if(fp == NULL){ fprintf(stderr, "파일 생성에 실패하였습니다.\n"); return FALSE; } fprintf(fp, "%c%c\n", 'P', '2'); fprintf(fp, "%d %d\n" , img->width, img->height); fprintf(fp, "%d\n", 255); int tmp; for(int i=0; i<img->height; i++){ for(int j=0; j<img->width; j++){ // 밝은곳은 더 밝게, 어두운 곳은 더 어둡게 if(img->pixels[i][j] > 125){ tmp = (img->pixels[i][j] - 125) * 0.3; tmp = img->pixels[i][j] + tmp; } else{ tmp = (125 - img->pixels[i][j]) * 0.3; tmp = img->pixels[i][j] - tmp; } // overflow, underflow 체크 if(tmp > 255){ tmp = 255; } else if(tmp < 0){ tmp = 0; } fprintf(fp, "%d ", tmp); } } fclose(fp); return TRUE; }
요건 소스가 다른 것들에 비해서 조금 복잡한데, 픽셀값 연산을 위한 계산식이 조금 복잡해서 그렇게 보이는 것이지 기본적으로 픽셀의 값을 조절한다는 점에서는 구조상 모두 동일합니다.
아래는 프로그램의 실행 결과입니다. 어떤가요?? 좀 더 느낌있어 보이나요~?
좀전에 위에서 overflow 체크를 안했을 경우에는 결과가 어떻게 나올지에 대해서도 실습을 해보겠다고 하였습니다. 아래는 영상을 밝게 처리할 때 overflow 로직을 주석처리 하고 실행한 결과 입니다.
이번 강의에서는 영상을 밝게/어둡게 하는 등 픽셀의 값(value)에 기반한 처리에 대해서 배워봤습니다. 지난번 강의에서도 살짝 언급했던 부분이기 때문에 크게 어려운 부분은 없었을 것 같네요. 강의에서 해보았던 효과들 말고 여러분 스스로 특별한 효과를 주는 프로그램을 작성해보시면 이해하는데도 도움이 되고 더 흥미도 갖을 수 있을 것 같네요~.
다음 강의에서는 이미지를 이동시키는 등 좌표에 기반한 처리에 대해서 알아보도록 하겠습니다.
혹시 궁금한 부분이나 잘못된 부분은 댓글로 남겨주세요~ 응원의 메시지도 환영입니다~ㅋ
이번 강의에 사용된 소스코드를 다운받으시려면 아래 파일을 클릭하세요.
'영상처리강좌' 카테고리의 다른 글
영상처리 강좌 - 7. 이미지 내 마음대로 움직여보자(2) : 크롭(Crop), 축소, 확대 (6) | 2016.01.03 |
---|---|
영상처리 강좌 - 6. 이미지 내 마음대로 움직여보자(1) : 이동(Move), 미러(Mirror), 플립(Flip) (6) | 2016.01.03 |
영상처리 강좌 - 쉬어가기 #1. 당신은 레나(Lenna)에 대해서 아시나요? (1) | 2016.01.03 |
영상처리 강좌 - 4. 실전! 이미지 읽어보기 (11) | 2016.01.03 |
영상처리 강좌 - 3. PBM 파일을 읽어보자! (15) | 2015.11.01 |