MATLAB 영상처리 활용

[MATLAB 영상처리 활용] Color Objects Detection/Segmentation

toyprojects 2023. 10. 20. 04:35

 

 

 

Image processing, computer vision 분야에서 이미지/동영상의 특정 objects를 검출하거나

움직임을 추적하는 방식으로써 SIFT, SURF 등의 알고리즘이 주로 사용됩니다.

이는 대상 objects의 특징검출(feature detection) - 예를들어 objects의 엣지, 코너등의 특징이

되는 점, 선, 면적등 - 과 image processing 테크닉이 결합되어 image matching을 수행 합니다. 

 

본 글에서는 도로를 달리는 빨간색의 자동차를 검출 (detection/segmentation)하는 쉽고 간단한 

알고리즘을 묘사하겠고, SIFT, SURF 등의 알고리즘을 이용하지 않습니다.

그리고 본 방식은 사용자의 개입을 일부 필요로 하며, 대상 objects의 검출에 있어 정확도가 

낮기 때문에 실용적으로 사용되지 않는 방식입니다.

 

원본 동영상은 본 글의 맨밑에 표시한 출처 1에서 다운로드 받을 수 있습니다.

 

 

 

[영상 1] Red-colored car detection/segmentation (출처 1)

 

 

 

대상 동영상에서 카메라는 고정되어 있으며, 여러 자동차들만이 움직이고 있습니다.

배경이 되는 나무, 도로, 표지판등은 움직이지 않고 햇빛의 영향으로 인한 intensity 변화가

적음을 알 수 있습니다. 

 

대상 동영상의 길이는 약 1분이며, frame rates는 약 50프레임으로써 총 3000프레임의 

영상데이터를 가집니다. 각 프레임의 영상은 720-by-1280 크기에 uint8 형식의 데이터를

갖습니다. 위의 [영상 1]은 파일 업로드 용량 관계상 첫 30프레임만을 처리하여 보여줍니다.

 

 

Load Video File

 

동영상을 workspace에 불러오기 위해 VideoReader( ) 함수에 파일명을 입력하였습니다.

그리고 각 프레임 영상데이터를 cell타입의 " frame " 변수에 프레임별로 저장하였습니다.

영상데이터를 변수에 저장하는 다른 방법으로 read( ) 함수가 있으며 이는 다차원의 이미지

데이터로써 반환함으로 변수 사용이 불편한 점이 있습니다. 

동영상을 workspace에 load 를 완료하였다면 반드시 video object를 해제해 주어야 합니다 -

clear(vidObj).

 

 

% Create a VideoReader object and display the total number of frames in the video.
vidObj = VideoReader("cars_on_highway.mp4");
num_frame = floor(vidObj.Duration * vidObj.FrameRate);
set_nFrame = num_frame;
frame = cell(1,set_nFrame);
frame_rate = vidObj.FrameRate;

% Read all of the frames, one frame at a time, by using the readFrame method, 
% and display the frames.
cnt = 1;
while hasFrame(vidObj)
   if cnt > set_nFrame
       break
   end
   frame{1,cnt} = readFrame(vidObj);   % 720x1280x3 size, uint8 class 
   cnt = cnt + 1;
end
clear vidObj

% Alternatively, you can read all the video frames at once. 
% The read method returns an m-by-n-by-p-by-3002(number of frame) array 
% (where each frame has size m-by-n-by-p) of video frames.
%allFrames = read(vidObj);

 

 

Image Processing by Trial and Error

- input parameters of  imbinarize( ),  bwareaopen( ),  strel( )

 

 

Workspace에 불러온 동영상 데이터 중에 우선 첫번째 프레임을 대상으로 이미지 프로세싱을

진행해 보겠습니다. 영상데이터 중에 빨간색 자동차를 검출하는것이 목적이기 때문에 RGB컬러 

이미지중 Red component 만을 이용하여 RGB컬러 이미지의 gray scale과 imsubtract( )를 수행

합니다. 그리고 나서 Otsu thresholding 으로써 이진화 이미지( "img_BW" ) 를 구합니다.

영상처리 진행중에 average 필터를 이용한 필터링 과정은 선택사항 입니다.

 

 

which_frame = 1;                                % 1st frame
avg_filter = fspecial('average',10);            % a blur filter

[r_ch,~,~] = imsplit(frame{1,which_frame});     % split color channel 
img_sub = imsubtract(r_ch, rgb2gray(frame{1,which_frame}));
img_sub = imfilter(img_sub,avg_filter,'replicate','conv'); % apply a blur filter
img_BW = imbinarize(img_sub);                   % binarization

 

 

빨간색 자동차는 첫번째 프레임 부터 대략 200번째 프레임 까지 나타나지만, 예를들어

1,000번째 프레임에는 나타나지 않습니다. 1,000번째 프레임 이미지에 위와 똑같은 

영상처리를 한 후 1번째 프레임과 비교를 하겠습니다.

 

밑의 [그림 1]의 A와 B는 각각 1번째, 1,000번째 프레임 이미지를 보이고, C와 D는 각각

A, B의 컬러채널 분리후 Red component만을 보여주고 있습니다. B에는 빨간색 자동차가

존재하지 않는 반면, A에는 두대의 빨간색 차량이 보이고 C에서 하얀색(Red 채널의 최고값

255)으로 보입니다. 물론, 하얀색 차량도 C에서는 하얀색(R,G,B 모두 최고값 255 가짐)으로

보입니다. 

 

그리고 Red component 와 각 RGB컬러 이미지의 gray scale 변환 데이터간의 영상차 - 

imsubtract( r_ch, rgb2gray(frame{1,which_frame}) ) - 결과를 E, F에 나타내고 있습니다.

결과에서 보듯이 빨간색 자동차의 영상성분은 E에 뚜렷이 존재하는 반면 F에는 나타나지

않습니다. 다만 영상 오른쪽 도로가에 빨간색 표시봉이 놓여져 있으므로 영상처리에 노이즈

로 남을 가능성이 있습니다.

 

 

[그림 1] 대상 이미지의 컬러채널 분리후 gray scale과의 영상차 ( imsubtract( ) )

 

 

만일 E와 F를 thresholding level 지정없이 기본값으로써 Otsu thresholding을 수행한다면 

BW이미지는 어떤 모습일까요? E의 경우 뚜렷한 빨간색 성분으로 인해 원하는 결과를 얻을

수 있겠지만, F의 binarization 변환은 기대와 다를것 입니다. 

 

빨간색 차량이 존재하는 첫번째 프레임과 존재하지 않는 1,000번째 프레임의 imsubtract( ) 

연산후 thresholding level을 구하면 각각 0.1922 그리고 0.0275 입니다. 따라서 앞으로는 

imbinarize( ) 명령어의 입력 파라메터 로써 임의값 0.15를 직접 지정할 것입니다.

 

 

% otsu thresholding level at 1st frame
graythresh(img_sub)

 

 

다음은 첫번째 프레임의 이진화(BW) 이미지를 상대로 morphological closing을 연산

합니다. Structuring element 로써 지름10픽셀의 disk 모양을 선택했습니다. 그리고 

closing 결과에서 구해진 objects들의 면적(= 픽셀합)들을 각 centroid에 표시하였습니다.

물론 structuring elements 의 크기와 모양에 의해 closing의 연산 결과가 달라지며, 이는

objects 검출 연산에 영향을 줍니다.

( structuring elements는 이글 참조, objects 면적 구하기는 이글 참조)

 

가장 앞쪽의 빨간색 차량의 차체면적은 11,478이고 지붕은 1,052 입니다. 자동차의 유리

성분 때문에 하나의 object로 인식하지 못하기 때문입니다. 

그리고 뒤 차량의 면적은 4,817 입니다. 마지막으로 오른편 길가에 있는 빨간색 표시봉

또한 object로써 검출되었고 면적은 742, 846 입니다. 

 

자동차의 차체와 지붕은 하나의 object로써 구성되야 하지만 연산과정의 어려움 때문에

지붕을 제거하고 차체만을 자동차 object로 검출할 것입니다. 그리고 도로의 표시봉 또한

objects 검출에 있어서 노이즈 이기 때문에 제거해야 할 대상입니다.

따라서 앞으로는 노이즈 제거 및 차량검출을 위해 bwareaopen( ) 명령어의 입력 파라메터

로써 임의값 1,600를 직접 지정할 것입니다.

( bwareaopen( )은 이글 참조)

 

 

 

[그림 2] 첫번째 프레임 BW이미지의 objects 면적

 

se_disk10 = strel('disk',10);             % a structuring element
imgC_disk10 = imclose(img_BW,se_disk10);  % morphological closing

obj_area = regionprops(imgC_disk10, 'Area');   
centroid = regionprops(imgC_disk10,'centroid');
centroid = cat(1, centroid.Centroid);

figure; imshow(imgC_disk10); hold on
for iter = 1:1:numel(obj_area)
    text(centroid(iter,1),centroid(iter,2), num2str(obj_area(iter).Area),...
         'Color','blue','FontSize',20,'FontWeight','bold');
end
hold off

 

 

 

Driving Car Detection / Segmentation

 

 

앞에서 사용자의 개입에 의한 trial and error 방식으로 얻어진 데이터를 이용하여 영상의

주행중인 빨간색 차량을 검출(detection/segmentation) 하고, 그것을 bounding box로 

본래 영상에 표시하겠습니다.  

 

코드를 간결하게 하기 위해 각 프레임 이미지의 binarization, morphological operations를 

하위함수에 정의하였고, 하나의 for-loop에서 첫번째 부터 지정된 프레임까지 이미지

프로세싱을 반복하여 수행합니다.

 

사용자가 지정한 3가지 변수, threshold level, structuring element, 제거할 obejcts 크기는

각각 "thresh_level", "se_disk6", "rmv_px" 에 지정되어 있습니다. 이 변수값에 의해 검출

결과는 달라질 것입니다.

 

첫번째 프레임에서의 빨간색 자동차 검출 이외에 뒤의 다른 프레임에서 검출결과를 밑의

[그림 3] 에서 보이고 있습니다. [그림 3]의 좌측 차량의 경우 영상에서 보이는 차체의 크기가

작아 먼거리에서는 검출이 되지 않았고 영상 가장 앞까지 와서야 검출이 되는 알고리즘의

문제가 있습니다. 

반면에 [그림 3]의 우측 차량은 빨간색이 차지하는 면적이 상대적으로 크기 때문에 먼거리

에서 부터 검출이 되었습니다.

 

검출된 objects에 bounding box를 표시하는 코드는 밑에 기재되었으며, 작업량이 많기 

때문에 waitbar( )를 이용하여 진행상황을 보여줍니다.

 

( 프레임별 objects 검출 결과를 하나의 동영상 혹은 gif 파일로 저장하려면 

  [MATLAB 영상처리 활용] 애니메이션 GIF 만들기 글을 참조하시기 바랍니다 )

 

 

[그림 3] 820번, 1500번 프레임의 자동차 검출 결과

 

 

% image processing

set_nFrame = num_frame;        
avg_filter = fspecial('average',10);    % a blur filter
se_disk6 = strel('disk',6);             % a structuring element
rmv_px = 1600;                          % remove oject smaller than this
thresh_level = 0.15;                    % Otsu thresholding level
img_BW_target = cell(1,set_nFrame);
bound_box = cell(1,set_nFrame);

f_wait = waitbar(0,'Please wait. The operation is processing');
for f_iter = 1:1:set_nFrame
    waitbar(f_iter/set_nFrame);
    
    % image binarization after image subtract between 
    % R-channel and its gray-scale
    img_BW = img_sub_and_binarization(frame{1,f_iter},thresh_level,avg_filter);
    
    % morphological closing with img_BW, and then
    % remove objects smaller than rmv_px [px], finally,
    % process bounding box position of target objects
    [img_BW_target{1,f_iter},bound_box{1,f_iter}] = ...
                            img_regional_process(img_BW,se_disk6,rmv_px);
end
close(f_wait)

% show result of driving car detection
fig = figure;
for f_iter = 1:1:set_nFrame
    
    % draw bounding box on (RGB)image
    imshow(frame{1,f_iter}); hold on
    for box_iter = 1:1:numel(bound_box{1,f_iter})
        rectangle('Position',bound_box{1,f_iter}(box_iter).BoundingBox,...
                  'EdgeColor','b','LineWidth',5);
    end
    hold off
    
    title_txt = ['\fontsize{20}Frame: ',num2str(f_iter)];
    title(title_txt);   
    
    cap_figure = getframe(fig);
    imgSet{1,f_iter} = cap_figure.cdata;
    pause(1/frame_rate)
end

% sub functions
function [img_BW] = img_sub_and_binarization(img,thresh_level,filt)
    [r_ch,~,~] = imsplit(img);                           % split color channel 
    img_sub = imsubtract(r_ch, rgb2gray(img));
    img_sub = imfilter(img_sub,filt,'replicate','conv'); % apply a filter
    img_BW = imbinarize(img_sub,thresh_level);           % binarization
end

function [img_ao,bound_box] = img_regional_process(img_BW,SE,rmv_px)
    imgC = imclose(img_BW,SE);             % morphological closing
    img_ao = bwareaopen(imgC,rmv_px);      % remove objects smaller than rmv_px [px]
    
    % [x y width height] of bounding box' upper-left corner
    bound_box = regionprops(img_ao,'BoundingBox');  
end

 

 

 

 

마지막으로 본 글에 쓰인 모든 MATLAB 코드는 밑에 표시해 두었습니다.

 

 

%% read video file

% Create a VideoReader object and display the total number of frames in the video.
vidObj = VideoReader("cars_on_highway.mp4");
num_frame = floor(vidObj.Duration * vidObj.FrameRate);
set_nFrame = floor(num_frame/2);        
frame = cell(1,set_nFrame);
frame_rate = vidObj.FrameRate;

% Read all of the frames, one frame at a time, by using the readFrame method, 
% and display the frames.
cnt = 1;
while hasFrame(vidObj)
   if cnt > set_nFrame
       break
   end
   frame{1,cnt} = readFrame(vidObj);   % 720x1280x3 size, uint8 class 
   cnt = cnt + 1;
end
clear vidObj

%% image processing

avg_filter = fspecial('average',10);    % a blur filter
se_disk6 = strel('disk',6);             % a structuring element
rmv_px = 1600;                          % remove oject smaller than this
thresh_level = 0.15;                    % Otsu thresholding level
img_BW_target = cell(1,set_nFrame);
bound_box = cell(1,set_nFrame);

f_wait = waitbar(0,'Please wait. The operation is processing');
for f_iter = 1:1:set_nFrame
    waitbar(f_iter/set_nFrame);
    
    % image binarization after image subtract between 
    % R-channel and its gray-scale
    img_BW = img_sub_and_binarization(frame{1,f_iter},thresh_level,avg_filter);
    
    % morphological closing with img_BW, and then
    % remove objects smaller than rmv_px [px], finally,
    % process bounding box position of target objects
    [img_BW_target{1,f_iter},bound_box{1,f_iter}] = ...
                            img_regional_process(img_BW,se_disk6,rmv_px);
end
close(f_wait)

% show result of driving car detection
fig = figure;
for f_iter = 1:1:set_nFrame
    
    % draw bounding box on (RGB)image
    imshow(frame{1,f_iter}); hold on
    for box_iter = 1:1:numel(bound_box{1,f_iter})
        rectangle('Position',bound_box{1,f_iter}(box_iter).BoundingBox,...
                  'EdgeColor','b','LineWidth',5);
    end
    hold off
    
    title_txt = ['\fontsize{20}Frame: ',num2str(f_iter)];
    title(title_txt);   
    
    cap_figure = getframe(fig);
    imgSet{1,f_iter} = cap_figure.cdata;
    pause(1/frame_rate)
end

%% sub functions

function [img_BW] = img_sub_and_binarization(img,thresh_level,filt)
    [r_ch,~,~] = imsplit(img);                           % split color channel 
    img_sub = imsubtract(r_ch, rgb2gray(img));
    img_sub = imfilter(img_sub,filt,'replicate','conv'); % apply a filter
    img_BW = imbinarize(img_sub,thresh_level);           % binarization
end

function [img_ao,bound_box] = img_regional_process(img_BW,SE,rmv_px)
    imgC = imclose(img_BW,SE);             % morphological closing
    img_ao = bwareaopen(imgC,rmv_px);      % remove objects smaller than rmv_px [px]
    
    % [x y width height] of bounding box' upper-left corner
    bound_box = regionprops(img_ao,'BoundingBox');  
end

 

 

 

 

 

 

 

 

 

출처1: https://www.pexels.com/video/cars-on-highway-854671/

Use all photos for free for commercial and noncommercial purposes.

https://www.pexels.com/creative-commons-images/