λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ’‘ EE's DEV/μ˜μƒμ²˜λ¦¬

[OpenCV] Convert color to grayscale, Image Resizing and Rotation

by Danna 2018. 9. 3.
728x90
728x90

Convert color image to grayscale image


1 Algorithm

 center position κ³Ό window size(BLK)λ₯Ό μž…λ ₯λ°›λŠ”λ‹€. μž…λ ₯λ°›λŠ” 것듀이 0보닀 μž‘μ„ κ²½μš°μ—λŠ” λ‹€μ‹œ μž…λ ₯ν•˜λ„λ‘ do-while둜 μ²˜λ¦¬ν•œλ‹€. (out of boundary) 


 μ‹œμž‘ν•˜λŠ” 지점을 startX, startY, λλ‚˜λŠ” 지점을 endX, endY 둜 μ •μ˜ν•œλ‹€.

 >  startX = (centerX - BLK < 0)? 0 : centerX - BLK;

endX = (centerX + BLK > width) ? width : centerX + BLK;

startY = (centerY - BLK < 0) ? 0 : centerY - BLK;

endY = (centerY + BLK > height) ? height : centerY + BLK;


 yμΆ• λ°˜λ³΅λ¬Έμ€ startY ~ endY, xμΆ• λ°˜λ³΅λ¬Έμ€ startX ~ endX κΉŒμ§€ λ°˜λ³΅ν•œλ‹€.

 > grayscale = (red + green + blue) / 3
 > red = green = blue = grayscale 


2 Code

#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
void main()
{
        int x, y, centerX, centerY, BLK;
        int startX, endX, startY, endY;
        Mat img = imread("test.jpg", CV_LOAD_IMAGE_COLOR);
        int width = img.cols;
        int height = img.rows;
        Mat Result = img.clone();
        do
        {
               printf("Input your center position and window size : ");
               scanf("%d %d %d", &centerX, &centerY, &BLK);
        
        } while (!(centerX >= 0 && centerY >= 0 && BLK > 0));
        
        startX = (centerX - BLK < 0)? 0 : centerX - BLK;
        endX = (centerX + BLK > width) ? width : centerX + BLK;
        startY = (centerY - BLK < 0) ? 0 : centerY - BLK;
        endY = (centerY + BLK > height) ? height : centerY + BLK;
        for (y = startY; y < endY; y++)
        {
               for (x = startX; x < endX; x++)
               {
                       int gray = (img.at<Vec3b>(y, x)[2] + img.at<Vec3b>(y, x)[1] + img.at<Vec3b>(y, x)[0]) / 3;
                       
                       Result.at<Vec3b>(y, x)[2] = gray;
                       Result.at<Vec3b>(y, x)[1] = gray;
                       Result.at<Vec3b>(y, x)[0] = gray;
               }
        }
        //imshow("color", img);
        imwrite("EE02_convert_color_to_gray.bmp", Result);
        printf("finished\n");
        waitKey(5000);
}


Image Resizing - NN(Nearest Neighbor)


  image resizing λ°©λ²•μ—λŠ” NN(Nearest Neighbor), Bi-linear, Bi-cubic μ„Έ 가지 방법이 μ‘΄μž¬ν•œλ‹€. λ‹€λ₯Έ 방법도 λ§Žλ‹€! 였늘 배운 λ‚΄μš©μ€ NN, Bi-linear 두 가지 방법이닀.


  μš°μ„  NN(Nearest Neighbor)을 μ΄μš©ν•΄ 두배 ν™•λŒ€, 두배 μΆ•μ†Œλ₯Ό κ°„λ‹¨νžˆ κ΅¬ν˜„ν•΄λ³΄μ•˜λ‹€. mini_pixel[3][3] 배열을 μ •μ˜ν•΄μ„œ 두배 ν™•λŒ€λ₯Ό ν–ˆκ³ , big_pixel[6][6] 배열을 μ •μ˜ν•΄μ„œ 두 λ°° μΆ•μ†Œλ₯Ό ν–ˆλ‹€. μ½”λ“œμ™€ κ²°κ³ΌλŠ” μ•„λž˜μ™€ κ°™λ‹€. up scaling을 μ μš©ν•  λ•Œμ—λŠ” λ°˜λ³΅λ¬Έμ„ κΈ°μ‘΄ μž‘μ€ 배열에 λ§žμΆ”μ–΄ λŒλ¦¬λ©΄μ„œ [y*2+0][x*2+0] κ³Ό 같이 μ ‘κ·Όν•˜μ—¬ 값을 λŒ€μž…ν–ˆλ‹€. down scaling은 큰 배열에 λ§žμΆ”μ–΄ λŒλ¦¬λ©΄μ„œ λ°˜λ³΅λ¬Έμ„ 2μΉΈ(down scaling λ²”μœ„)μ”© λ›°μ–΄λ„˜μ–΄ [y/2][x/2] 와 같이 μ ‘κ·Όν•˜μ—¬ 값을 λŒ€μž…ν–ˆλ‹€. λ‘˜ λ‹€ input에 λ§žμΆ°μ„œ λ°˜λ³΅λ¬Έμ„ 돌리면 λ˜λŠ” 것 κ°™λ‹€!



1 Up scaling μ½”λ“œ
 

        printf("2x up-scaling \n- - - - - - - - - - \n");
        for (y = 0; y < 3; y++)
        {
               for (x = 0; x < 3; x++)
               {
                       up_scaling[y * 2 + 0][x * 2 + 0] = mini_pixel[y][x];
                       up_scaling[y * 2 + 0][x * 2 + 1] = mini_pixel[y][x];
                       up_scaling[y * 2 + 1][x * 2 + 0] = mini_pixel[y][x];
                       up_scaling[y * 2 + 1][x * 2 + 1] = mini_pixel[y][x];
               }
        }

2 Down Scaling μ½”λ“œ 

        printf("1/2 down-scaling \n- - - - - - - - - - \n");
        for (y = 0; y < 6; y+=2)
        {
               for (x = 0; x < 6; x+=2)
               {
                       down_scaling[(int)(y / 2)][(int)(x / 2)] = big_pixel[y][x];
               }
        }



Image Resizing - Bi-linear interpolation 


  image resizing 을 ν•˜λ©΄μ„œ λ§Œμ•½ 0.7 배율둜 ν•œλ‹€λ©΄, κΈ°μ‘΄ (1, 1)μ’Œν‘œ 값은 (0.7, 0.7)이 λœλ‹€. 이 픽셀이 κ°–κ²Œ λ˜λŠ” 값을 κ³„μ‚°ν•  λ•Œ μ£Όλ³€ 4개의 픽셀을 μ΄μš©ν•΄ weighted sum 을 μ·¨ν•œλ‹€. ν”½μ…€μ˜ 값을 계산할 λ•Œ forward filling, backward filling 두 가지 방식이 μžˆλŠ”λ° forward filling은 input image μ’Œν‘œμ—μ„œ result image μ’Œν‘œλ‘œ scale 을 κ³±ν•΄μ£ΌλŠ” 방식이고, backward filling 방식은 result image κ°€ μžˆλ‹€κ³  κ°€μ •ν•˜μ—¬, κ·Έ μ’Œν‘œμ— 1/scale 을 κ³±ν•΄ input image μ—μ„œ μ›λž˜ μ–΄λ–€ μœ„μΉ˜μ— μ‘΄μž¬ν–ˆλŠ”κ°€λ₯Ό μ°Ύμ•„κ°€λŠ” 방식이닀. 

  

  λ‚΄κ°€ μ‚¬μš©ν•œ λ³€μˆ˜λŠ” result image의 μ’Œν‘œλŠ” x, y 둜 μ •μ˜ν–ˆκ³  input image의 μ’Œν‘œλŠ” posX = x / scale, posY = y/scale 이라고 μ •μ˜ν–ˆλ‹€. scale이 λ‚˜λˆ μ§„ 값이기 λ•Œλ¬Έμ— posX, posY λŠ” float dataκ°€ 될 것이며 (int)posX, (int)posX + 1, (int)posY, (int)posY + 1 값듀을 μ΄μš©ν•΄μ„œ μ£Όλ³€ 4개 ν”½μ…€ κ°’μœΌλ‘œ μ΅œμ’… ν”½μ…€ 값을 κ³„μ‚°ν•œλ‹€. 핡심적인 뢀뢄은 μ•„λž˜ μ½”λ“œμ΄λ‹€. λ¬Όλ‘ , result κ°μ²΄λŠ” 미리 μ •μ˜ν•΄λ‘μ–΄μ•Όν•œλ‹€.


        for (y = 0; y < result.rows-1; y++)
        {
               for (x = 0; x < result.cols-1; x++)
               {
                       posX = x / scale;
                       posY = y / scale;
                       pre_posX = (int)posX;
                       next_posX = pre_posX + 1;
                       pre_posY = (int)posY;
                       next_posY = pre_posY + 1;
                       if (next_posX > width || next_posY > height)
                              continue;
                       //printf("(y, x) = (%d, %d) (posY, posX) = (%.2f, %.2f) ", y, x, posY, posX);
                       //printf("pre_posX, next_posX, pre_posY, next_posY : %d %d %d %d ", pre_posX, next_posX, pre_posY, next_posY);
                       for (i = 0; i < 3; i++)
                       {
                              posY_L[i] = (next_posY - posY)*img.at<Vec3b>(pre_posY, pre_posX)[i] + (posY - pre_posY)*img.at<Vec3b>(next_posY, pre_posX)[i];
                              // -> green
                              posY_R[i] = (next_posY - posY)*img.at<Vec3b>(pre_posY, next_posX)[i] + (posY - pre_posY)*img.at<Vec3b>(next_posY, next_posX)[i];
                              // -> pink
                              posX_U[i] = (next_posX - posX)*img.at<Vec3b>(pre_posY, pre_posX)[i] + (posX - pre_posX)*img.at<Vec3b>(pre_posY, next_posX)[i];
                              // -> yellow
                              posX_D[i] = (next_posX - posX)*img.at<Vec3b>(next_posY, pre_posX)[i] + (posX - pre_posX)*img.at<Vec3b>(next_posY, next_posX)[i];
                              // -> blue
                              new_pixel[i] = ((next_posX - posX)*posY_L[i] + (posX - pre_posX)*posY_R[i] + (next_posY - posY)*posX_U[i] + (posY - pre_posY)*posX_D[i]) / 2;
                              
                              result.at<Vec3b>(y, x)[i] = new_pixel[i];
                       }
                       //printf("-> %d %d %d\n", new_pixel[2], new_pixel[1], new_pixel[0]);
               }
        }


Image rotation with forward filling


  Input image(img 객체)λ₯Ό μ›ν•˜λŠ” μž…λ ₯ κ°’(scale degree)으둜 νšŒμ „μ‹œμΌœ Output image(result 객체)에 ν”½μ…€ λ‹¨μœ„λ‘œ κ³„μ‚°ν•˜μ—¬ μ €μž₯ν•œλ‹€. Output image(result 객체)λŠ” input image와 μ‚¬μ΄μ¦ˆλŠ” κ°™λ‹€λŠ” 점도 κ³ λ €ν•΄μ€€λ‹€.

  μž…λ ₯ 받은 각도(scale degree)λŠ” μœ‘μ‹­λΆ„λ²•μ΄κΈ° λ•Œλ¬Έμ—, λ‹€μŒ 식에 μ˜ν•˜μ—¬ ν˜Έλ„λ²•μœΌλ‘œ λ³€ν™˜ν•΄μ€€λ‹€. radian = scale * PI / 180 으둜 κ³„μ‚°ν•œ ν›„ μ‚Όκ°ν•¨μˆ˜ 계산 μ‹œμ—λŠ” radian 값을 μ΄μš©ν•œλ‹€. 


  Rotation matrix 와 [x y]λ₯Ό ν–‰λ ¬ κ³±ν•œ κ²°κ³ΌλŠ” [posX posY] 이닀. posX = x * cos(radian) – y * sin(radian), posY = x * sin(radian) + y * cos(radian) 으둜 계산해쀀닀. 


  μ—¬κΈ°μ„œλŠ” Input image의 쀑심 지점을 κΈ°μ€€μœΌλ‘œ νšŒμ „ν•΄μ•Ό ν•˜λ―€λ‘œ μœ„μ˜ μ‹μ—μ„œ λ³€ν˜•ν•΄μ€€λ‹€. posX = (x-centerX) * cos(radian) – (y-centerY) * sin(radian) + centerX, posY = (x-centerX) * sin(radian) + (y-centerY) * cos(radian) + centerY 으둜 κ³„μ‚°ν•œλ‹€.


  핡심적인 μ½”λ“œλŠ” λ‹€μŒκ³Ό κ°™λ‹€.




  κ²°κ³Ό 사진은 10도, 45도, -45도 0도 νšŒμ „ν•œ 사진이닀. 180도 νšŒμ „ν–ˆμ„ λ•ŒλŠ” 검은색 선이 μƒκΈ°λ©΄μ„œ 쑰금 깨진닀. μ•½κ°„μ˜ 깨짐은 μžˆμ§€λ§Œ, νšŒμ „μ€ μ •μƒμ μœΌλ‘œ λ˜λŠ” 것을 ν™•μΈν–ˆλ‹€.




Image rotation with bi-linear interpolation


  Input image(img κ°μ²΄)λ₯Ό μ›ν•˜λŠ” μž…λ ₯ κ°’(scale degree)으둜 νšŒμ „μ‹œμΌœ Output image(result 객체)에 ν”½μ…€ λ‹¨μœ„λ‘œ κ³„μ‚°ν•˜μ—¬ μ €μž₯ν•œλ‹€. Output image(result 객체)λŠ” input image와 μ‚¬μ΄μ¦ˆλŠ” κ°™λ‹€λŠ” 점도 κ³ λ €ν•΄μ€€λ‹€.


  μž…λ ₯ 받은 각도(scale degree)λŠ” μœ‘μ‹­λΆ„λ²•μ΄κΈ° λ•Œλ¬Έμ—, λ‹€μŒ 식에 μ˜ν•˜μ—¬ ν˜Έλ„λ²•μœΌλ‘œ λ³€ν™˜ν•΄μ€€λ‹€. radian = scale * PI / 180 으둜 κ³„μ‚°ν•œ ν›„ μ‚Όκ°ν•¨μˆ˜ 계산 μ‹œμ—λŠ” radian 값을 μ΄μš©ν•œλ‹€. 

  Backward filling λ°©μ‹μœΌλ‘œ μš°μ„  result 의 x, y μ’Œν‘œλ₯Ό 가지고 input image의 μ’Œν‘œ posX, posY 값을 μ°ΎλŠ”λ‹€. 값을 μ°ΎκΈ° μœ„ν•΄μ„œλŠ” μœ„μ—μ„œ μ‚¬μš©ν•œ rotation matrix의 inverse matrixλ₯Ό μ°Ύμ•„μ„œ 계산해쀀닀. 쀑심을 κΈ°μ€€μœΌλ‘œ 계산해주어야 ν•˜κΈ° λ•Œλ¬Έμ—, 쀑심 μ’Œν‘œ(centerX, centerY) λ³€μˆ˜λ₯Ό μ΄μš©ν•΄ μ•„λž˜ 식을 κ³„μ‚°ν•΄μ£Όμ—ˆλ‹€.

  μ΅œμ’… 역행렬은 [[cos -sin][sin cos]] 이고, posX = (x-centerX) * cos(radian) + (y-centerY) * sin(radian) + centerX, posY = -(x-centerX) * sin(radian) + (y-centerY) * cos(radian) + centerY 으둜 input image의 μ’Œν‘œ 값을 μ°Ύμ•„μ€€λ‹€.


  μ°Ύμ•„λ‚Έ μ’Œν‘œλŠ” float 값이기 λ•Œλ¬Έμ— bi-linear interpolation(μ–‘λ°©ν–₯ μ„ ν˜• 보간법)을 μ΄μš©ν•΄μ„œ μ£Όλ³€ 4개의 μ’Œν‘œλ“€μ— κ°€μ€‘μΉ˜λ₯Ό μ£Όμ–΄ ν”½μ…€ 값을 κ³„μ‚°ν•œλ‹€. 



  Bi-linear interpolation 방식을 μ΄μš©ν•˜μ—¬ 깨짐이 μ—†μŒμ„ ν™•μΈν–ˆλ‹€.


728x90
728x90