-1

I'm currently running some data analysis on a lot of pictures and the code i have running is the following:

close all
clear all
clc

A=imread('Ring_1_frame_120.jpg');       %Load picture
                                        %A01-A010 = xmin ymin width height 
                                        %for all vials
A001=imcrop(A,[65 159 95 332]);
A002=imcrop(A,[182 161 95 332]);
A003=imcrop(A,[297 164 95 332]);
A004=imcrop(A,[402 165 90 332]);
A005=imcrop(A,[495 168 90 332]);
A006=imcrop(A,[606 166 90 332]);
A007=imcrop(A,[705 171 90 332]);
A008=imcrop(A,[808 175 90 332]);
A009=imcrop(A,[922 175 90 332]);
A0010=imcrop(A,[1031 175 90 332]);

w = who; % returns the names of all your current variables in a cell.

for i = 1:numel(w)
    % A00 is unique to all the variables you want to process.
    if ~isempty(strfind(w{i}, 'A00')) 
        % hard coding greenChannel and extracting the second plane.
        eval(['greenChannel = ',w{i},'(:,:,2)']); 
        BW = edge(greenChannel,'Prewitt');
           %figure, imshow(BW);

    %Dialate Lines
       se90 = strel('line', 3, 90);
       se0 = strel('line', 3, 0);
       BWsdil = imdilate(BW, [se90 se0]);
            %figure, imshow(BWsdil), title('dilated gradient mask');

    %Fill Lines
      BWdfill = imfill(BWsdil, 'holes');
            %figure, imshow(BWdfill), title('binary image with filled holes');
    %Clean up borders  
      BWnobord = imclearborder(BWdfill, 4);
            %figure, imshow(BWnobord), title('cleared border image');
    %Final cleanup
      seD = strel('diamond',1);
      BWfinal = imerode(BWnobord,seD);
      BWfinal = imerode(BWfinal,seD);
            figure, imshow(BWfinal), title('segmented image');

      L = bwlabel(BWfinal);
      s = regionprops(L,'centroid');
      data(:,:,i) = s; %save the xy coords as data matrix 
    end
end

The goal I'm trying to achieve is getting the variable s into a csv file, but I'm stuck at the last line since it's not working. It keeps overwriting itself. s is a structure ranging from 3x1 to 5x1 and I have also tried to use struct2cell and mat2cell but that was unsuccessful.

rayryeng
  • 102,964
  • 22
  • 184
  • 193
Mikkel Astrup
  • 405
  • 6
  • 18

2 Answers2

3

s is a structure, so what you need to do is unpack the structure so that it becomes a matrix, then you can save the matrix to file. s contains a field called Centroid, so you need to access that field.

However before I address that point, checking to see how many variables are in your workspace so you can determine how many times your loop has to iterate.... is very bad practice. Especially if you are using each variable name as a separate occurrence for processing. I highly recommend you use a structure to encapsulate this or some sort of cell array.

If I can provide a canonical post, please consult user Adriaan's excellent post on how to avoid dynamic variable names and sheds light on what I'm about to talk about here.

Something like this would work instead. I'll use a cell array because (at least to me) it is easier. Place your desired coordinates in a 2D matrix where each row is the top-left corner of the location in the image you want to process as well as the width and height (basically suitable for imcrop), then loop over each set of coordinates and place the cropped image as an element in a cell array. Cell array use is important because the dimensions per cropped image are different and so you can't use a normal matrix here:

A=imread('Ring_1_frame_120.jpg');       %Load picture
                                        %A01-A010 = xmin ymin width height 

coords = [65 159 95 332; 182 161 95 332; 297 164 95 332; 402 165 90 332;...
          495 168 90 332; 606 166 90 332; 705 171 90 332; 808 175 90 332;...
          922 175 90 332; 1031 175 90 332];

numImages = size(coords,1);
images = cell(1,numImages);

for ii = 1 : numImages
    images{ii} = imcrop(A,coords(ii,:));
end

images is now a cell array of cropped images that belong to the image A. To access the right image, you can use images to do that like so:

img = images{ii};

ii is the image number you wish to access. Another comment I'd like to make is your use of eval. It is really not recommended in your loop either... which is why I decided to change the logic.

Do this instead:

for ii = 1 : numImages
    % hard coding greenChannel and extracting the second plane.
    greenChannel = images{ii}(:,:,2); %// Change for green channel

    %// Now code is the same as before
    BW = edge(greenChannel,'Prewitt'); 
    %figure, imshow(BW);

    %Dilate Lines
    se90 = strel('line', 3, 90);
    se0 = strel('line', 3, 0);
    BWsdil = imdilate(BW, [se90 se0]);
    %figure, imshow(BWsdil), title('dilated gradient mask');

    %Fill Lines
    BWdfill = imfill(BWsdil, 'holes');
    %figure, imshow(BWdfill), title('binary image with filled holes');

    %Clean up borders  
    Wnobord = imclearborder(BWdfill, 4);
    %figure, imshow(BWnobord), title('cleared border image');

    %Final cleanup
    seD = strel('diamond',1);
    BWfinal = imerode(BWnobord,seD);
    BWfinal = imerode(BWfinal,seD);
    figure, imshow(BWfinal), title('segmented image');

   ...
end

Alright, so now how do we get the coordinates of the centroid and save them to file? You simply need to unpack the structure and get the centroid coordinates. Make sure data is declared at the top is now a cell array:

data = cell(1, numImages);

The reason why you need a cell array (again) is because you don't know how many segmented components there are per cropped image you're looking at. Now finally at the end of your loop:

for ii = 1 : numImages
   %// Your code...
   %//...

   L = bwlabel(BWfinal);
   s = regionprops(L,'centroid');

   %// New code
   data{ii} = reshape([s.Centroid],2,[]).';
end

Now that you have the centroid coordinates stored in a cell array per cropped image, you can either create multiple CSVs where each CSV contains the centroids of each detected object for each cropped image, or you can concatenate all of the centroids together in a single matrix.

So, do either:

for ii = 1 : numImages
    csvwrite(sprintf('data%d.csv', ii), data{ii});
end

... or

out = cat(1, data{:});
csvwrite('data.csv', out);

I'm not sure which method you want to use to write to file, but either of those should work.

Community
  • 1
  • 1
rayryeng
  • 102,964
  • 22
  • 184
  • 193
0

You need to access struct elements using s(i).Centroid, as a minimal example,

a =imread('circlesBrightDark.png');
bw = a < 100;
s = regionprops(bw,'centroid');

for i =1:size(s)
    data(:,:,i) = s(i).Centroid
end
Ed Smith
  • 12,716
  • 2
  • 43
  • 55