Search code examples
matlabimage-processingfeature-detectionimage-segmentationfeature-extraction

Grayscale segmentation/feature extraction/blob detection?


I'm trying to find a starting point, but I can't seem to find the right answer. I'd be very grateful for some guidance. I also don't know the proper terminology, hence the title.

  1. I took an image of a bag with a black background behind it.
  2. And I want to extract the bag, similar to this.
  3. And if possible, find the center, like this.

Essentially, I want to be able to extract the blob of pixels and then find the center point.

I know these are two separate questions, but I figured if someone can do the latter, then they can do the first. I am using MATLAB, but would like to write my own code and not use their image processing functions, like edge(). What methods/algorithms can I use? Any papers/links would be nice (:


Solution

  • Well, assuming that your image only consists of a black background and a bag inside it, a very common way to perform what you're asking is to threshold the image, then find the centroid of all of the white pixels.

    I did a Google search and the closest thing that I can think of that matches what you want looks like this:

    http://ak.picdn.net/shutterstock/videos/3455555/preview/stock-footage-single-blank-gray-shopping-bag-loop-rotate-on-black-background.jpg

    This image is RGB for some reason, even though it's grayscale so we're going to convert this to grayscale. I'm assuming you can't use any built-in MATLAB functions and so rgb2gray is out. You can still implement it yourself though as rgb2gray implements the SMPTE Rec. 709 standard.

    Once we read in the image, you can threshold the image and then find the centroid of all of the white pixels. That can be done using find to determine the non-zero row and column locations and then you'd just find the mean of both of them separately. Once we do that, we can show the image and plot a red circle where the centroid is located. As such:

    im = imread('http://ak.picdn.net/shutterstock/videos/3455555/preview/stock-footage-single-blank-gray-shopping-bag-loop-rotate-on-black-background.jpg');
    %// Convert colour image to grayscale
    im = double(im);
    im = 0.299*im(:,:,1) + 0.587*im(:,:,2) + 0.114*im(:,:,3);
    im = uint8(im);
    
    thresh = 30; %// Choose threshold here
    
    %// Threshold image
    im_thresh = im > thresh;
    
    %// Find non-zero locations
    [rows,cols] = find(im_thresh);
    
    %// Find the centroid
    mean_row = mean(rows);
    mean_col = mean(cols);
    
    %// Show the image and the centroid
    imshow(im); hold on;
    plot(mean_col, mean_row, 'r.', 'MarkerSize', 18);
    

    When I run the above code, this is what we get:

    enter image description here

    Not bad! Now your next concern is the case of handling multiple objects. As you have intelligently determined, this code only detects one object. For the case of multiple objects, we're going to have to do something different. What you need to do is identify all of the objects in the image by an ID. This means that we need to create a matrix of IDs where each pixel in this matrix denotes which object the object belongs to. After, we iterate through each object ID and find each centroid. This is performed by creating a mask for each ID, finding the centroid of that mask and saving this result. This is what is known as finding the connected components.

    regionprops is the most common way to do this in MATLAB, but as you want to implement this yourself, I will defer you to my post I wrote a while ago on how to find the connected components of a binary image:

    How to find all connected components in a binary image in Matlab?

    Mind you, that algorithm is not the most efficient one so it may take a few seconds, but I'm sure you don't mind the wait :) So let's deal with the case of multiple objects now. I also found this image on Google:

    We'd threshold the image as normal, then what's going to be different is performing a connected components analysis, then we iterate through each label and find the centroid. However, an additional constraint that I'm going to enforce is that we're going to check the area of each object found in the connected components result. If it's less than some number, this means that the object is probably attributed to quantization noise and we should skip this result.

    Therefore, assuming that you took the code in the above linked post and placed it into a function called conncomptest which has the following prototype:

    B = conncomptest(A);
    

    So, take the code in the referenced post, and place it into a function called conncomptest.m with a function header such that:

    function B = conncomptest(A)
    

    where A is the input binary image and B is the matrix of IDs, you would do something like this:

    im = imread('http://cdn.c.photoshelter.com/img-get2/I0000dqEHPhmGs.w/fit=1000x750/84483552.jpg');
    
    im = double(im);
    im = 0.299*im(:,:,1) + 0.587*im(:,:,2) + 0.114*im(:,:,3);
    im = uint8(im);
    
    thresh = 30; %// Choose threshold here
    
    %// Threshold image
    im_thresh = im > thresh;
    
    %// Perform connected components analysis
    labels = conncomptest(im_thresh);
    
    %// Find the total number of objects in the image
    num_labels = max(labels(:));
    
    %// Find centroids of each object and show the image
    figure;
    imshow(im);
    hold on;
    
    for idx = 1 : num_labels
        %// Find the ith object mask
        mask = labels == idx;
    
        %// Find the area
        arr = sum(mask(:));
    
        %// If area is less than a threshold
        %// don't process this object
        if arr < 50
            continue;
        end
    
        %// Else, find the centroid normally
        %// Find non-zero locations
        [rows,cols] = find(mask);
    
        %// Find the centroid
        mean_row = mean(rows);
        mean_col = mean(cols);
    
        %// Show the image and the centroid
        plot(mean_col, mean_row, 'r.', 'MarkerSize', 18);
    end
    

    We get:

    enter image description here