Search code examples
matlabimage-processingcomputer-visionimage-segmentationmatlab-cvst

How to plot boundary and centroids on video frames called inside step() function


I am calling some images inside a for loop and then doing some processing on those images. After that, I am using the step function to display those frames and their masks inside a video player. How can I add a boundary to an object inside the mask image? Also, how can I make the boundary thicker and plot the centroids of each blob in the mask in the mask image? Below is the rough sketch of the code.

   videoPlayer = vision.VideoPlayer();
   maskPlayer = vision.VideoPlayer();
  for ii = 1:nfiles
  filenameii = [............]
  frame= imread(filenameii);
  mask = dOB(frame,BackgroundImg);
% some processing on the images
  mask= bwareaopen(mask,27);
  boundaries = bwboundaries(mask,'noholes');
  B=boundaries{1};
  Centroid = regionprops(mask,'centroid');
  Centroids = cat(1, Centroid.Centroid);
  plot(B(:,2),B(:,1),'g','LineWidth',3);
  plot(Centroids(:,1), Centroids(:,2), 'r+', 'MarkerSize', 10);  step(videoPlayer,frame);
  step(maskPlayer, mask); 

P.S: I know how to display it on a figure using hold on but I would like this done directly on the image before displaying it in the video player. Any guidance would be appreciated.


Solution

  • Simply paint the pixels on the mask first before displaying it in the video player. What you have does work, but it will plot the boundary inside the figure for the mask player. Therefore, take your boundaries that you detected from bwboundaries, create linear indices from these coordinates and set the values in your image to white. What may be even simpler is to take your mask that you detected and use bwperim to automatically produce a mask that contains the boundaries of the blobs. I also see that you are filling in the holes of the mask, so you can use imfill directly on the output of your post-processing so that it gives you an image instead of coordinates. You would then use this mask to directly index into your image and set the coordinates of the boundaries of the blob to your desired colour. If you desire to make the perimeter thicker, a simple image dilation with imdilate using the appropriately sized square structuring element will help. Simply define the size of the neighbourhood of this structuring element to be the thickness of the perimeter that you desire. Finally, if you want to insert the centroids into the mask and since you have the MATLAB Computer Vision System Toolbox, use the insertMarker function so that you can use a set of points for each centroid and put them directly in the image. However, you must be sure to change the mask from a logical to a data type more suitable for images. uint8 should work. Therefore, cast the image to this type then multiply all nonzero values by 255 to ensure the white colours are maintained in the mask. With insertMarker, you want to insert red pluses with a size of 10 so we need to make sure we call insertMarker to reflect that. Also, because you want to have a colour image you will have to make your mask artificially colour and to do this painting individually for each plane for the colour that you want. Since you want green, this corresponds to the RGB value of (0,255,0).

    Therefore, I have modified your code so that it does this. In addition, I've calculated the centroids of the filled mask instead of the original. We wouldn't want to falsely report the centroids of objects with gaps... unless that's what you're aiming for, but let's assume you're not:

    videoPlayer = vision.VideoPlayer();
    maskPlayer = vision.VideoPlayer();
    
    % New - Specify colour you want
    clr = [0 255 0]; % Default is green
    
    % New - Define thickness of the boundaries in pixels.
    thickness = 3;
    
    % New - Create structuring element
    se = strel('square', thickness);
    
    for ii = 1:nfiles
        filenameii = [............]
        frame = imread(filenameii);
        mask = dOB(frame, BackgroundImg);
        % some processing on the images
        mask = bwareaopen(mask,27);
        %boundaries = bwboundaries(mask,'noholes');
        %B=boundaries{1};
    
        % New code - fill in the holes
        mask = imfill(mask, 'holes');
    
        Centroid = regionprops(mask,'centroid');    
    
        % New code - Create a boundary mask
        mask_p = bwperim(mask, 8);
    
        % New code - Make the boundaries thicker
        mask_p = imdilate(mask_p, se);
    
        % New code - create a colour image out of the mask
        [red, green, blue] = deal(255*uint8(mask));
    
        % Paint the perimeter of the blobs in the desired colour
        red(mask_p) = clr(1); green(mask_p) = clr(2); blue(mask_p) = clr(3);        
    
        Centroids = cat(1, Centroid.Centroid);
        %plot(B(:,2),B(:,1),'g','LineWidth',3);
        %plot(Centroids(:,1), Centroids(:,2), 'r+', 'MarkerSize', 10);  
    
        % New - Make mask into RGB image for marker painting and to 
        % show to the user
        mask_p = cat(3, red, green, blue);
    
        % New - Insert the centroids directly in the mask image
        mask_p = insertMarker(mask_p, Centroids, '+', 'color', 'r', 'size', 10);
    
        step(videoPlayer, frame);
    
        % New - Show new mask in the player
        step(maskPlayer, mask_p); 
    end