--- title: "계산영상시스템 과제1" layout: post --- assignment1

Contents

Initials

픽셀의 data type이 uint16임으로 16 bits로 이루어져있음 이미지의 width는 4290, height는 2856임

img = imread('./assign1/data/banana_slug.tiff');
disp(class(img));
fprintf("Width : %d\n", size(img, 2));
fprintf("Height : %d\n", size(img, 1));
double_img = double(img);
uint16
Width : 4290
Height : 2856

Linearization

이미지 픽셀의 최대값을 15000, 최소값을 2047으로 가정하여 normalization을 하고 1보다 큰 값을 1로 0보다 작은 값을 0으로 설정함

img_max = 15000;
img_min = 2047;

norm_img = (double_img - img_min)/(img_max - img_min);
norm_img(norm_img > 1) = 1;
norm_img(norm_img < 0) = 0;
imshow(norm_img*5);

Identifying the correct Bayer pattern

스크립트 맨 아래에 bayer_pattern 함수가 선언되어있음 주어진 bayer pattern 4개에 대해서 함수가 구현되어있으며 각 패턴에 따른 이미지의 결과는 다음과 같음

rgb_img = bayer_pattern(norm_img, 'grbg');
imshow(rgb_img*5);
rgb_img_c = bayer_pattern(norm_img, 'rggb');
imshow(rgb_img_c*5);
rgb_img = bayer_pattern(norm_img, 'bggr');
imshow(rgb_img*5);
rgb_img = bayer_pattern(norm_img, 'gbrg');
imshow(rgb_img*5);

4개의 pattern 중에서 다른 3개의 pattern에 비하여 RGGB 패턴의 경우는 초록색 필터를 적용한 것과 같은 느낌을 주지만 목표로 하는 이미지의 색상 조합으로 인식할 수 있음 따라서 RGGB Bayer pattern이 적합함

White balancing

white world와 gray world balancing에 사용된 식은 수업자료를 참고하였음 이미지를 RGB로 분리하여 식을 적용하고 다시 1D 이미지로 합쳐줌

r_img = norm_img(1:2:end, 1:2:end);
g_img = norm_img(1:2:end, 2:2:end);
g_img = [g_img, norm_img(2:2:end, 1:2:end)];
b_img = norm_img(2:2:end, 2:2:end);

white world R = R/R_MAX*G_MAX G = G B = B/B_MAX*G_MAX

r_max = max(r_img(:));
g_max = max(g_img(:));
b_max = max(b_img(:));

white_r = r_img/r_max*g_max;
white_b = b_img/b_max*g_max;

white_img = norm_img;
for i = 1:1428
    for j = 1:2145
        white_img(i*2-1, j*2-1) = white_r(i, j);
        white_img(i*2, j*2) = white_b(i, j);
    end
end
imshow(white_img*5);

gray world R = R/R_MEAN*G_MEAN G = G B = B/B_MEAN*G_MEAN

r_mean = mean(r_img(:));
g_mean = mean(g_img(:));
b_mean = mean(b_img(:));

gray_r = r_img/r_mean*g_mean;
gray_b = b_img/b_mean*g_mean;

gray_img = norm_img;
for i = 1:1428
    for j = 1:2145
        gray_img(i*2-1, j*2-1) = gray_r(i, j);
        gray_img(i*2, j*2) = gray_b(i, j);
    end
end
imshow(gray_img*5);

RGB 이미지가 아닌 상태로는 어떠한 white balancing 방식이 적합한지 구분하기 어려움 따라서 임의로 RGB 이미지로 변환 후 white balancing 방식을 선택하였음

tmp_img = zeros(2856, 4290, 3);
r_max = max(rgb_img_c(:,:,1));
g_max = max(rgb_img_c(:,:,2));
b_max = max(rgb_img_c(:,:,3));
tmp_img(:,:,1) = rgb_img_c(:,:,1)/r_max*g_max;
tmp_img(:,:,2) = rgb_img_c(:,:,2);
tmp_img(:,:,3) = rgb_img_c(:,:,3)/b_max*g_max;
imshow(tmp_img*5);
r_mean = mean(rgb_img_c(:,:,1));
g_mean = mean(rgb_img_c(:,:,2));
b_mean = mean(rgb_img_c(:,:,3));
tmp_img(:,:,1) = rgb_img_c(:,:,1)/r_mean*g_mean;
tmp_img(:,:,2) = rgb_img_c(:,:,2);
tmp_img(:,:,3) = rgb_img_c(:,:,3)/b_mean*g_mean;
imshow(tmp_img*5);
% 따라서 gray world white balancing을 선택하였음

Demosaicing

Bilinear interpolation rggb R과 B의 경우에는 interpolation2d 함수를 그래도 사용이 가능함 하지만 G의 경우에는 함수를 그래도 사용하기에는 체스판 무늬처럼 픽셀들이 위치해있어서 적합하지 않으므로 세로의 위치가 일치하는 픽셀끼리 모아서 2개의 배열로 나누어 함수를 사용함

demos_img = zeros(2856, 4290, 3);
base_r = gray_img(1:2:end, 1:2:end);
base_g1 = gray_img(1:2:end, 2:2:end);
base_g2 = gray_img(2:2:end, 1:2:end);
base_b = gray_img(2:2:end, 2:2:end);

[x, y] = meshgrid((1:1:4290), (1:1:2856));
[x2, y2] = meshgrid((1:1:4290), (2:2:2856));
[x1, y1] = meshgrid((1:1:4290), (1:2:2856));

demos_img(:,:,1) = interp2(1:2:4290, 1:2:2856, base_r, x, y);
demos_img(1:2:end,:,2) = interp2(1:2:4290, 1:2:2856, base_g1, x1, y1);
demos_img(2:2:end,:,2) = interp2(1:2:4290, 2:2:2856, base_g2, x2, y2);
demos_img(:,:,3) = interp2(2:2:4290, 2:2:2856, base_b, x, y);

imshow(demos_img*4);

Brightness adjustment and gamma correction

grayscale로 변환한 이미지의 최대값과 최소값은 0과 1사이로 맞추면 이미지의 전체적인 밝기가 밝아지는 대신에 일부 매우 밝은 부분에 맞춰서 이미지의 밝기가 조정됨 따라서 최대값이 아닌 일부 매우 밝은 부분을 제외할 수 있는 99.9%에 위치한 값을 최대값 1로 맞춰서 밝기를 조절하고 1를 초과하는 값들을 1로 맞춰줌.

grayscale = rgb2gray(demos_img);
scale = 1/max(grayscale(:));
brightness_img = min(1, demos_img*scale);
imshow(brightness_img);

scale = 1/prctile(grayscale(:), 99.9);
brightness_img = min(1, demos_img * scale);
imshow(brightness_img);
gamma_img = brightness_img;
gamma_img(gamma_img<=0.0031308) = gamma_img(gamma_img<=0.0031308)*12.92;
gamma_img(gamma_img>=0.0031308) = (1+0.055) * power(gamma_img(gamma_img>=0.0031308), 1/2.4)-0.055;

imshow(gamma_img);

Compression

PNG의 경우 무손실 압축을 JPEG의 경우 일부 정보를 무시하는 손실 압축을 사용함. 완벽하게 95프로가 아닌 대략 95.2프로 정도의 압축결과를 보여줌

imwrite(gamma_img, "uncompression.png");
imwrite(gamma_img, "compression.jpg", 'quality', 95);

uncomress_img = dir("uncompression.png");
comress_img = dir("compression.jpg");

disp(uncomress_img.bytes/comress_img.bytes);
    4.7626

function rgb_img = bayer_pattern(norm_img, pattern)
    if pattern == 'grbg'
        g1 = norm_img(1:2:end, 1:2:end);
        r = norm_img(1:2:end, 2:2:end);
        b = norm_img(2:2:end, 1:2:end);
        g2 = norm_img(2:2:end, 2:2:end);
    elseif pattern == 'rggb'
        r = norm_img(1:2:end, 1:2:end);
        g1 = norm_img(1:2:end, 2:2:end);
        g2 = norm_img(2:2:end, 1:2:end);
        b = norm_img(2:2:end, 2:2:end);
    elseif pattern =='bggr'
        b = norm_img(1:2:end, 1:2:end);
        g1 = norm_img(1:2:end, 2:2:end);
        g2 = norm_img(2:2:end, 1:2:end);
        r = norm_img(2:2:end, 2:2:end);
    elseif pattern == 'gbrg'
        g1 = norm_img(1:2:end, 1:2:end);
        b = norm_img(1:2:end, 2:2:end);
        r = norm_img(2:2:end, 1:2:end);
        g2 = norm_img(2:2:end, 2:2:end);
    end

    rgb_img = zeros(2856, 4290, 3);
    for i = 1:1428
        for j = 1:2145
            rgb_img(i*2-1, j*2-1, 1) = r(i, j);
            rgb_img(i*2-1, j*2-1, 2) = g1(i, j);
            rgb_img(i*2-1, j*2-1, 3) = b(i, j);

            rgb_img(i*2-1, j*2, 1) = r(i, j);
            rgb_img(i*2-1, j*2, 2) = g1(i, j);
            rgb_img(i*2-1, j*2, 3) = b(i, j);

            rgb_img(i*2, j*2-1, 1) = r(i, j);
            rgb_img(i*2, j*2-1, 2) = g2(i, j);
            rgb_img(i*2, j*2-1, 3) = b(i, j);

            rgb_img(i*2, j*2, 1) = r(i, j);
            rgb_img(i*2, j*2, 2) = g2(i, j);
            rgb_img(i*2, j*2, 3) = b(i, j);
        end
    end
end