How can I plot x and y RGB values of an image to analyze?

I am analyzing the results of an optical test. In essence, the samples generate a halo as seen in the picture attached. Good samples are those that have mostly black in the middle and a green halo on the outside ( ring shape ).
I want to write a script that imports the image looks at the RGB ( in order to get color intensity). Then plots each image in a 3D plot. In my mind it would look something like valley since the exterior has the largest intenisty and the interior is black. The idea is to analyze a large enough set of data that I can then create a threshold for how much illumniation I can allow in the center before the product is considered bad.
I have tried using Imread to get the RGB values. Then taking the Green portion and plotting that using both surf and plot with no success. Any help and guidance is appreciated.

3 件のコメント

You say that surf() does not work for you, but you do not talk about what you need to see in a plot.
filename = 'https://www.mathworks.com/matlabcentral/answers/uploaded_files/1076765/knifetest.JPG';
img = imread(filename);
imshow(img);
G = img(:,:,2);
surf(G, 'edgecolor', 'none')
imshow(G)
SnooptheEngineer
SnooptheEngineer 2022 年 7 月 25 日
@Walter Roberson Thank you for your answer. First of all the color map was in black only. Second of all, I wanted to plot the x,y cordinate for each pixel with green intensity so I can go about analyzing several images and eliminating those that have light in the center of the ring. The idea is to have the least amount of light inside the ring.
Walter Roberson
Walter Roberson 2022 年 7 月 25 日
What is the mapping between row and columns to x and y, if the surf() is not the plot you need?

サインインしてコメントする。

 採用された回答

William Rose
William Rose 2022 年 7 月 25 日

0 投票

Try the following:
im1=imread('knifetest1.jpg');
zr=im1(:,:,1); %get the red intensity array
zg=im1(:,:,2); %get the green intensity array
zb=im1(:,:,3); %get the blue intensity array
[r,c]=size(zg); %image dimensions
surf(1:c,1:r,zg,'EdgeColor','none'); %surface plot of green intensity
zlabel('Green Intensity')
This produces a 3D plot which you can rotate. It looks reasonable to me. You can also plot the red and blue intensities, zr and zb.
Good luck.

14 件のコメント

SnooptheEngineer
SnooptheEngineer 2022 年 7 月 25 日
Thanks for your quick follow through. How would I go about isolating certain portions of the shape to analyze all the images? The idea is to have the least amount of light inside the outer ring shape? Bascially once a certain threshold (light intensity in the middle) is passed, the sample fails.
William Rose
William Rose 2022 年 7 月 25 日
編集済み: William Rose 2022 年 7 月 25 日
The answer to your question depends on how you want to define the boundary of the outer ring shape.
im1=imread('knifetest1.jpg');
zg=im1(:,:,2); %get the green intensity array
[r,c]=size(zg); %image dimensions
surf(1:c,1:r,zg,'EdgeColor','none'); %surface plot of green intensity
xlabel('X'); ylabel('Y'); zlabel('Green Intensity')
hold on
In this case, it appears that a rectangle from x=200 to 500 and from y=200 to 300 will roughly coincide with the central region. (As always, the rows and columns of matrix zg correspond to columns and rows, respectively, of the image.)
xmin=200;xmax=500; ymin=200; ymax=300; %bounds of the region of interest
xbox=[xmin,xmin,xmax,xmax,xmin]; ybox=[ymin,ymax,ymax,ymin,ymin]; zbox=100*ones(5,1);
plot3(xbox,ybox,zbox,'r','Linewidth',2);
view(90,90)
I assume you want to integrate the intensity inside the region of interest. If the average intensity exceeds a threshold, the sample fails.
avgIntensity=sum(sum(zg(ymin:ymax,xmin:xmax)))/((ymax-ymin+1)*(xmax-xmin+1));
fprintf('Average intensity in ROI=%.1f\n',avgIntensity);
Average intensity in ROI=4.4
Try that.
SnooptheEngineer
SnooptheEngineer 2022 年 7 月 26 日
編集済み: SnooptheEngineer 2022 年 7 月 26 日
Thank you William. This is very similar to what I want. My goal is to identify and isolate the higher intensity peaks that make up the halo ring. Then identify the bounderies inside the halo with the lower intensity colors as you pointed out. If the intensity inside the halo identified is higher than the threshold the part fails and vice versa.
Some questions on the code itself and issues I ran into if you dont mind explaining:
  1. why did you have a xbox with four intervals that are set up differently than ybox ( x min,xmax,xmax,xmin) vs (ymin,ymax,ymax,ymin,ymin).
  2. What is the zbox for? Would that be the red boundry you selected
  3. Could you walk me through the integration equation? I havent done that before in Matlab
  4. Can you add a subplot that includes the surf and 2D image with boundary highlighted?
  5. The image seems to get inverted when its plotted on the surf plot. I tried switching the r and c axis around but it didnt work. I am attaching the image with the correct orientation. You'll notice the surf plot and intensity plots both invert the image.
Thank you
-----------------------
im1=imread('knifetest.jpg');
zr=im1(:,:,1); %get the red intensity array
zg=im1(:,:,2); %get the green intensity array
zb=im1(:,:,3); %get the blue intensity array
[r,c]=size(zg); %image dimensions
surf(1:c,1:r,zg,'EdgeColor','none'); %surface plot of green intensity
zlabel('Green Intensity')
xmin=200;xmax=500; ymin=200; ymax=300; %bounds of the region of interest
xbox=[xmin,xmin,xmax,xmax,xmin]; ybox=[ymin,ymax,ymax,ymin,ymin]; zbox=100*ones(5,1);
plot3(xbox,ybox,zbox,'r','Linewidth',2);
view(90,90)
avgIntensity=sum(sum(zg(ymin:ymax,xmin:xmax)))/((ymax-ymin+1)*(xmax-xmin+1));
fprintf('Average intensity in ROI=%.1f\n',avgIntensity);
William Rose
William Rose 2022 年 7 月 26 日
  1. why did you have a xbox with four intervals that are set up differently than ybox ( x min,xmax,xmax,xmin) vs (ymin,ymax,ymax,ymin,ymin).
  2. What is the zbox for? Would that be the red boundry you selected
  3. Could you walk me through the integration equation? I havent done that before in Matlab
  4. Can you add a subplot that includes the surf and 2D image with boundary highlighted?
  5. The image seems to get inverted when its plotted on the surf plot. I tried switching the r and c axis around but it didnt work. I am attaching the image with the correct orientation. You'll notice the surf plot and intensity plots both invert the image.
Q1 and Q2: I wanted to show the location of the boundary for integration on the 3D surface plot. If I plotted it as a 2D plot, it would be underneath the surface plot. So I plotted it as a 3D plot. The box in 3D has 5 corners because the last point is a repeat of the first point, to complete the box. The line zbox=100*ones(1,5) creates z coordinates of the 5 points, and the value 100 is chosen because I was confident that 100 would be higher than the surface, so the red lines would not be hidden. The order of xbox=[xmin,xmin,xmax,...] is different from ybox=[ymin,ymax,ymax,...] , in order to go from corner 1 to 2 to 3 to 4 to 1. The command view(90,90) produces a viewpoint from directly overhead of the surface and the red rectangle (which is floating at an altitude of 100).
Q3. The line avgIntensity=sum(sum(zg(ymin:ymax,xmin:xmax)))/((ymax-ymin+1)*(xmax-xmin+1)); can be thought of as avgIntnsity=numerator/denominator. sum(zg(ymin:ymax,xmin:xmax)) is the sum of the elements of the 2D array zg(), from ymin to ymax, and from xmin to xmax. Sum(), when applied to a 2D array, does a sum of each column, so the output is a vector whose elements are hte sums of each clumn. The I do a second, outer sum(), to ads up all the elements of the vector returned by the inner sum(). That completes the numerator. The denominator, (xmax-xmin+1)*(ymax-ymin+1), is simply the number of elements, or pixels, that we did the sum(sum(...)) over. The ratio numerator/denominator is the average intensity per pixel.
Q4. I'm not sure I understand what you want there. Do you want to drape the image over the mountain range?
Q5. You are right: the image is flipped, because images have y=0 at the top and increasing downward, but x increases to the right, for images and for standard plots, so one axis is flipped, but not the other axis. I should have fixed this with set(gca,'YDir','reverse') , to make the y axis increase in the donward direction, as is standard for images. Then I would probably need to alter the angles in the view() command.
William Rose
William Rose 2022 年 7 月 26 日
Note that, in addition to the flipping of the y axis, rows and columns of an image correspond to coumns and rows, respectively, of a Matlab array. So the "x" and "y" are flipped from what we're used to. You can transpose the array if this bothers you.
I feel self-conscious talking about this stuff when @Image Analyst is on the case. @Image Analyst knows a lot more than me anout Matlab and image analysis.
SnooptheEngineer
SnooptheEngineer 2022 年 7 月 26 日
@William Rose Thank you for your immense help. I really appreciate your detailed response. Honestly, I learned more from this post than a couple of hours of seraching through questions on Matlab community. @Image Analystt is a savage , I have come accorss a few of his posts. Nonethelss, you are amazing as well! So thank you!
As a follow up and to clarify my questions:
Q4: I was wondering if there was a way to place the origianl image , the overhead view and surface plot on one plot as we do in sub plots.
  1. Would I place the set gca immediatly after imshow ?
  2. If I want to define the border limits using intensity of light. How would I go about that? If you run the code on the second image, you'll find the border completely miss the point. I am trying to avoid going to each sample and defining the border.
  3. For the sum why did you add and subtract by one? Does it have to do with degrees of freedom?
  4. Finally, your knowledge is great. What resources do you recommend for becoming better at Matlab? Any books you recommend? I was looking at Matlab's training courses but those are really $$$
William Rose
William Rose 2022 年 7 月 26 日
@OmartheEngineer, @Image Analyst says it is easy to find the halo, so I suggest you find out from them how to find the halo (defined as halomask). Use imageAnalyst's formula for the mean intensity inside the halo:
propsG = regionprops(haloMask, g, 'MeanIntensity');
Reject the sample if propsG exceeds the critical value.
William Rose
William Rose 2022 年 7 月 27 日
Thank you very much for your kind comments.
  1. I will get back to you on this.
  2. I think the script by @Image Analyst does what you are requesting: it finds the boundary in an automatic way. The script does a histogram of the intensitites in the image. I htink the script uses that histogram to esitmate a level for bondary detection. Then it founds ponts on the bounday and draws a "convex hull" (i.e. a convex shape) around or inside the points that it finds.
  3. The denominator for the average intensity is (xmax-xmin+1)*(ymax-ymin+1) because (for example) zg(10:20,10:40) has 11x31 elements.
  4. I bought two books about Matlab in 1998 when I started a new job where I needed to know Matlab. This 2022 review of Matlab textbooks is nice: https://computingforgeeks.com/best-books-to-learn-matlab-programming/. The first book reviewed is in the 6th edition and is published by Cengage. Six editions means it has a history of success, which I understand because a textbook I co-authored is coming out with its 3rd edition soon. Cengage is known for publishing easy-to-follow texts; I have written four chapters of a Cengage textbook.
William Rose
William Rose 2022 年 7 月 27 日
編集済み: William Rose 2022 年 7 月 27 日
[edited: Added code to flip y axis; add red rectangle to middle plot; create custom color map and apply it to bottom plot; added discussion of the colormap and of the default orientation.]
You asked: "I was wondering if there was a way to place the original image , the overhead view and surface plot on one plot as we do in sub plots. Would I place the set gca immediatly after imshow?"
Here is some code that does this.
im1=imread('knifetest.jpg');
[zr,zg,zb]=imsplit(im1); %extract colors as separate arrays
%[r,c]=size(zg); %image dimensions
%next line: create custom color map with shades of green only
mymap=[zeros(256,1),[0:1/255:1]',zeros(256,1)]; %custom color map
figure;
subplot(3,1,1); imshow(im1); %display original image
subplot(3,1,2); surf(zg,'EdgeColor','none'); %display surface plot
axis equal; %make each unit on each axis have same length, so that aspect ratio matches imshow()
axis tight; %limit each axis's extent to the data range
set(gca,'Ydir','reverse'); %flip y axis
view(0,90); %view from above
%next line defines rectangle coordinates (point 1=point 5, to complete)
xbox=[200,200,500,500,200]; ybox=[200,300,300,200,200]; zbox=100*ones(1,5);
hold on;
plot3(xbox,ybox,zbox,'-r','Linewidth',2) %draw red rectangle on middle plot
subplot(3,1,3); surf(zg,'EdgeColor','none'); %display surface plot in 3D
colormap(mymap) %apply custom colormap to surfaces
You can rotate the bottom plot by clicking the 3D-rotate-icon in the plot window, then clicking and dragging inside the plot area. You could also rotate the middle plot, but you said you want to see it from above, so don't.
I created a green-only colormap, and applied it to the surfaces. This makes it look like the original image has been draped over the 3D surface, even though it has not been. Comment out the last line of the script, if you prefer Matlab's default colormap. Colormap info here.
When I open knifetest.jpg with Windows Photos or Paint 3D, it opens in portrait orientation. When I display it in Matlab with imshow(), it appears in landscape. I don't regard this as a problem, in this case. If it bothers you, there is a solution, see here. It involves reading the image metadata, and rotating if necessary.
SnooptheEngineer
SnooptheEngineer 2022 年 8 月 1 日
Thank you for your help and insight. I am sorry for going MIA. I got into a deep hole with your and Image Analyst's approach. Yours is simple and works for one sample. However, I am looking for a way to use this script for a wide variety of parts. I couldnt choose who's answer is best honestly, Matlab automatically selected yours. Nonethless, I am grateful for both of your help
My first approach involved creating a for loops that reads each pixel value. The goal was for me to start scanning from the top left corner while reading the pixel value. Once I read a value above threshold it's set as reference. After that once, I read a value that is well below the first threshold I esablished, that pixel is assigned the xmin,ymax coordinate (top left corner of my rectangle).Setting that as reference, I read the pixel values on that same y axis (scan left to right) until I hit that threshold identifying the top right corner.
Then I repeat the process but starting my scan from the bottom of the image. 4 of the 6 points identified, would be used to create the rectangle for the region of interest.
That said, I was not successul in my appraoch as the code seems to skip the left side of the rectangle complete. I think part of it is the threshold value. I was choosing random numbers. I want to try using
@Image Analyst of converting the image to gray scale and then use that with my for loop approach?
Thank you for your book recommendations, I actually just bought the Esesential matlab by Brian Hahn.Does the first book you mention cover image analysis and how to communicte and drive sensors/motors ?
------------------------
filename='knifetest.jpg'
im=imread(filename);
[r,c,numofcolors]=size(im);
green=im(:,:,2);
%ginput function that allows user to select points
% r=1:row;
% c=1:col;
for x= 152:c %increment from 1 to last pixel in image
for y= 1:r %increment from 1 to last pixel in image
if im(y,x,2)>200
% [ymaxU1, XminU1] = [y,x]
ymaxU1= y
xminU1= x
for y= ymaxU1:r %increment from 1 to last pixel in image
% for x= xminU1:c %increment from 1 to last pixel in image
if im(y,xminU1,2)<30
% [ymaxU2, XminU2]= [y,x]
ymaxU2=y;
% xminU2=x;
end
end
end
end
end
for y= r:-1:1 %increment from bottom left corner of rectangle (y coordinate)
for x= 1:c %increment from bottom left corner of rectangle (x coordinate)
if im(y,x,2)>70
% [yminL1,XminL1]= [y,x]
yminL1=y;
% xminL1=x;
for y= yminL1:-1:1 %increment from last pixel to first pixel in image
% % for x= xminU1:1 %increment from 1 to last pixel in image
if im(y,x,2)<30
% [yminL2,XminL2]= [y,x]
yminL2=y;
% xminL2=x;
end
end
end
end
end
% r2=flipr
%%Now we want to identify opposite corners of rectangle
for x= c:-1:1
for y= 1:ymaxU2
if im(ymaxU2,x,2)>30
% [ymaxRU2,xmaxU2] = [y,x]
ymaxRU2 =y;
xmaxU2=x;
end
end
end
for x= c:-1:1
if im(yminL2,x,2)>30
% [yminRL2,xmaxL2]= [y,x]
yminRL2=y;
xmaxL2=x;
end
end
im1=imread(filename);
[zr,zg,zb]=imsplit(im1); %extract colors as separate arrays
%[r,c]=size(zg); %image dimensions
%next line: create custom color map with shades of green only
mymap=[zeros(256,1),[0:1/255:1]',zeros(256,1)]; %custom color map
figure;
subplot(3,1,1); imshow(im1); %display original image
subplot(3,1,2); surf(zg,'EdgeColor','none'); %display surface plot
axis equal; %make each unit on each axis have same length, so that aspect ratio matches imshow()
axis tight; %limit each axis's extent to the data range
set(gca,'Ydir','reverse'); %flip y axis
view(0,90); %view from above
%next line defines rectangle coordinates (point 1=point 5, to complete)
xbox=[xminU1,xminU1,xmaxU2,xmaxU2,xminU1 ]; ybox=[yminL1,ymaxU2,ymaxU2,yminL2,yminL2]; zbox=100*ones(1,5);
hold on;
plot3(xbox,ybox,zbox,'-r','Linewidth',2) %draw red rectangle on middle plot
subplot(3,1,3); surf(zg,'EdgeColor','none'); %display surface plot in 3D
colormap(mymap) %apply custom colormap to surfaces
William Rose
William Rose 2022 年 8 月 1 日
If I were you, I would work with the solution of @Image Analyst. If it does not work for some of the images you have, then I would try to figure out why. I like the fact that the solution of @Image Analyst produces a mask, or region of interest, that fits nicely inside the boundaries of the object in your original image. I have not tried to run @Image Analyst's solution. Here are some lines from their solution that I think are particularly interesting. You could make modifications when analyzing other images:
lowThreshold = 85;
highThreshold = 255;
% Use interactive File Exchange utility by Image Analyst to to the interactive thresholding.
% https://www.mathworks.com/matlabcentral/fileexchange/29372-thresholding-an-image?s_tid=srchtitle
% [lowThreshold, highThreshold] = threshold(114, 255, grayImage);
mask = grayImage >= lowThreshold & grayImage <= highThreshold;
grayImage is your grayscale image (the green channel, for example), with levels form 0 to 255. "mask = grayimage..." creates a binary image which is 1 (i.e. white) wherever grayImage is between the low and high thresholds, and 0 (black) elsewhere. Since highThreshold=255 (which is the max possible value in grayImage), the line "mask=grayImage..." has the effect of setting mask to 1 wherever grayImage is >= lowThreshold. This mask image is displayed at the lower left of the 6-panel display. You could adjust the value lowThreshold to a number different than 85, if necessary.
% Now do clean up by hole filling, and getting rid of small blobs.
mask = ~bwareaopen(mask, 6); % Take blobs larger than 6 pixels only.
% Erode the mask so that we have an ROI within the outer boundaries.
se = strel('disk', 18, 0);
mask = imerode(mask, se);
The lines above are some of the steps that convert the bottom left mask image to the final mask, which is shown at bottom center of the 6-panel display. If you want the final mask to be closer to/farther from the edges of the boundary, try making the disk radius less than/greater than 18.
% Get the convex hull
mask = bwconvhull(mask, 'union');
The line above fills in any concave parts of the ROI just enough so that the ROI no longer has any concave parts. You could comment out this line, if you want to experiment with non-convex ROIs, for certain test images.
SnooptheEngineer
SnooptheEngineer 2022 年 8 月 5 日
@William Rose, Thank you for getting back to me and taking the extra time to explain the code. I played around with both contrast and what Image analyst called blop elimnation size. In both instances, the bad sample's border could not be identified. I think the code needs to be smarter. At this point, I cant tell for certain whats wrong until I spend more time understanding the functions line by line. Anyway, I didnt want to take too much time before thanked you again the extra mile you went and your help. I will update this thread in the next couple of weeks incase I get better results as I dive deeper into Matlab
William Rose
William Rose 2022 年 8 月 5 日
@OmartheEngineer, you are welcome. Good luck with your work.
Image Analyst
Image Analyst 2022 年 8 月 5 日
Why can't you use a fixed template and look at the same part of the image all the time? Does your part move around in the field of view? Does it change size or shape? Does your camera move around? Is there anyway you can eliminate those things by using a jig to place your part and making your camera mounting brackets very rigid and secure?

サインインしてコメントする。

その他の回答 (2 件)

Image Analyst
Image Analyst 2022 年 7 月 26 日

2 投票

Here is a quick and dirty way. It could be made better with more programming. Also if you knew the shape of the interior in advance then we could use that and locate it and align it with the image to get a better mask shape that doesn't depend on the threshold.
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 16;
%===============================================================================
% Get the name of the image the user wants to use.
baseFileName = 'knifetest.jpg';
folder = pwd;
fullFileName = fullfile(folder, baseFileName);
% Check if file exists.
if ~exist(fullFileName, 'file')
% The file doesn't exist -- didn't find it there in that folder.
% Check the entire search path (other folders) for the file by stripping off the folder.
fullFileNameOnSearchPath = baseFileName; % No path this time.
if ~exist(fullFileNameOnSearchPath, 'file')
% Still didn't find it. Alert user.
errorMessage = sprintf('Error: %s does not exist in the search path folders.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
%=======================================================================================
% Read in demo image.
rgbImage = imread(fullFileName);
% Get the dimensions of the image.
[rows, columns, numberOfColorChannels] = size(rgbImage)
% Crop off screenshot stuff
% rgbImage = rgbImage(132:938, 352:1566, :);
% Display image.
subplot(2, 3, 1);
imshow(rgbImage, []);
impixelinfo;
axis on;
caption = sprintf('Original Color Image\n%s', baseFileName);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
% Set up figure properties:
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0 0.05 1 0.95]);
% Get rid of tool bar and pulldown menus that are along top of figure.
% set(gcf, 'Toolbar', 'none', 'Menu', 'none');
% Give a name to the title bar.
set(gcf, 'Name', 'Demo by ImageAnalyst', 'NumberTitle', 'Off')
drawnow;
% Take one of the color channels, whichever one seems to have more contrast.
grayImage = max(rgbImage, [], 3);
% Display the image.
subplot(2, 3, 2);
imshow(grayImage, []);
title('Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
axis('on', 'image');
drawnow;
%=======================================================================================
% Show the histogram
subplot(2, 3, 3);
imhist(grayImage);
grid on;
caption = sprintf('Histogram of Gray Scale Image');
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
xlabel('Gray Level', 'FontSize', fontSize)
ylabel('Count', 'FontSize', fontSize)
%=======================================================================================
% Threshold the image to get the disk.
lowThreshold = 85;
highThreshold = 255;
% Use interactive File Exchange utility by Image Analyst to to the interactive thresholding.
% https://www.mathworks.com/matlabcentral/fileexchange/29372-thresholding-an-image?s_tid=srchtitle
% [lowThreshold, highThreshold] = threshold(114, 255, grayImage);
mask = grayImage >= lowThreshold & grayImage <= highThreshold;
xline(lowThreshold, 'Color', 'r', 'LineWidth',2);
xline(highThreshold, 'Color', 'r', 'LineWidth',2);
% Find out the size of all the blobs so we know what size to use when filtering with bwareaopen.
props = regionprops(mask, 'Area');
allAreas = sort([props.Area]);
% Display the mask image.
subplot(2, 3, 4);
imshow(mask, []);
title('Initial Mask', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
axis('on', 'image');
drawnow;
% Now do clean up by hole filling, and getting rid of small blobs.
mask = ~bwareaopen(mask, 6); % Take blobs larger than 6 pixels only.
% Erode the mask so that we have an ROI within the outer boundaries.
se = strel('disk', 18, 0);
mask = imerode(mask, se);
% Hopefully there are two blobs at this point.
% Remove background
mask = imclearborder(mask);
% There should be only one at this point, but just to be sure, extract the largest blob.
mask = bwareafilt(mask, 1);
% Get the convex hull
mask = bwconvhull(mask, 'union');
% Display the mask image.
subplot(2, 3, 5);
imshow(mask, []);
title('Final Mask', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
axis('on', 'image');
drawnow;
% Plot the borders of all the blobs in the overlay above the original grayscale image
% using the coordinates returned by bwboundaries().
% bwboundaries() returns a cell array, where each cell contains the row/column coordinates for an object in the image.
% Here is where we actually get the boundaries for each blob.
boundaries = bwboundaries(mask);
% boundaries is a cell array - one cell for each blob.
% In each cell is an N-by-2 list of coordinates in a (row, column) format. Note: NOT (x,y).
% Column 1 is rows, or y. Column 2 is columns, or x.
numberOfBoundaries = size(boundaries, 1); % Count the boundaries so we can use it in our for loop
% Here is where we actually plot the boundaries of each blob in the overlay.
subplot(2, 3, 1);
hold on; % Don't let boundaries blow away the displayed image.
for k = 1 : numberOfBoundaries
thisBoundary = boundaries{k}; % Get boundary for this specific blob.
x = thisBoundary(:,2); % Column 2 is the columns, which is x.
y = thisBoundary(:,1); % Column 1 is the rows, which is y.
plot(x, y, 'r-', 'LineWidth', 2); % Plot boundary in red.
end
hold off;
caption = sprintf('Original image with %d Outlines, from bwboundaries()', numberOfBoundaries);
title(caption, 'FontSize', fontSize);
axis('on', 'image'); % Make sure image is not artificially stretched because of screen's aspect ratio.
% Mask the image and show the masked image.
subplot(2, 3, 6);
maskedImage = grayImage; % Initialize.
maskedImage(~mask) = 0; % Erase outside the mask.
imshow(maskedImage, [])
title('Masked Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
axis('on', 'image');
drawnow;
hold on;
plot(x, y, 'r-', 'LineWidth', 2); % Plot boundary in red.
% Find out the size of all the remaining blobs.
props = regionprops(mask, grayImage, 'Area', 'MeanIntensity');
caption = sprintf('Area = %d pixels. Mean Intensity = %.2f', props.Area, props.MeanIntensity)
title(caption, 'FontSize', fontSize);
uiwait(helpdlg('Done!'));

2 件のコメント

William Rose
William Rose 2022 年 7 月 26 日
Wow. Impressive.
SnooptheEngineer
SnooptheEngineer 2022 年 8 月 1 日
編集済み: SnooptheEngineer 2022 年 8 月 1 日
Thank you very much for taking the time to help. I am sorry for going MIA. I got into a deep hole going over both your solutions.Honestly, your code was slightly overwhelming but nonethless very impressive. I tried running it for the other image but it didnt work.
As I mentioned earlier, I am looking for a way to use this script for a wide variety of parts. I tried to modify your approach by using a series of nested for loops to scan through the image and read pixel values to establish the edges of the image ( once a certain threshold is met)
We start scanning from the top left corner while reading the pixel value. Once I read a value above threshold it's set as reference. After that once, I read a value that is well below the first threshold I esablished, that pixel is assigned the xmin,ymax coordinate (top left corner of my rectangle).Setting that as reference, I read the pixel values on that same y axis (scan left to right) until I hit that threshold identifying the top right corner.
Then I repeat the process but starting my scan from the bottom of the image. 4 of the 6 points identified, would be used to create the rectangle for the region of interest.
That said, I was not successul in my appraoch as the code seems to skip the left side of the rectangle complete. Please ignore my draft code below. I am just trying to show the upper level thought process. I think my issue lies with establishing the threshold value. My goal is to create a rectangle inside the region of interest.
I see two ways forward:
  1. Using your appraoch of switching the image to a gray scale and trying to identify light vs no light then using these thresholds in a series of nested loops
2. Have the user somehow identify or select the region of interest. Then using @William Rose's approach to intergtate the intensity (Ask user to select four points to highlight rectangular region). However, I would probably need to divide the region of interest ( red rectangle) into a smaller set of squares and set a pass/fail threshold invididually
Thanks again for your help. I really appreicate your time and effort. Your insight will help me know assess how deep into the rabbit hole I need to go before making a decision on this approach
P.S: I inlcluded the old bad knife image sample that didnt work with your code.

サインインしてコメントする。

Image Analyst
Image Analyst 2022 年 7 月 25 日

0 投票

You don't need to do a surf plot of anything. Do you just want to determine the average R, G, and B values inside the halo? Or max values or standard deviation? Then just find the halo mask (not hard) and do
[r, g, b] = imsplit(rgbImage);
propsR = regionprops(haloMask, r, 'MeanIntensity');
propsG = regionprops(haloMask, g, 'MeanIntensity');
propsB = regionprops(haloMask, b, 'MeanIntensity');
Let me know if you can't figure out how to get the region of interest inside the halo boundary. You can probably threshold and then do some morphological clean up to get that shape.

3 件のコメント

SnooptheEngineer
SnooptheEngineer 2022 年 7 月 26 日
編集済み: SnooptheEngineer 2022 年 7 月 26 日
Thank you for your response ! I ran your code subbing rgbImage for my filename string and it didnt work. It gave me the following errors.
--------------------------
Error using imsplit
Expected input number 1, I, to be one of these types:
double, single, uint8, uint16, uint32, uint64, int8, int16, int32, int64, logical
Error in imsplit (line 54)
validateattributes(I,{'numeric','logical'},{'3d','nonsparse','real','nonempty'},'imsplit','I',1);
Error in knifeedgepractice (line 1)
[r, g, b] = imsplit('knifetest.jpg');
-------------------------------------
My goal is to identify and isolate the higher intensity peaks that make up the halo ring. Then identify the bounderies inside the halo with the lower intensity colors as you pointed out. If the intensity inside the halo identified is higher than the threshold the part fails and vice versa.
Image Analyst
Image Analyst 2022 年 7 月 26 日
You didn't use the right variable. You used the filename, not the image. You need to do this:
rgbImage = imread('knifetest.jpg');
[r, g, b] = imsplit(rgbImage);
SnooptheEngineer
SnooptheEngineer 2022 年 7 月 26 日
I did that and got a different error this time. Do I need to define HaloMask ? Thats the only thing I can think of. BTW, your posts on Matlab have been great to read and I appreciate your help :)
--------------------
Unrecognized function or variable 'haloMask'.
Error in knifeedgepractice (line 4)
propsR = regionprops(haloMask, r, 'MeanIntensity');

サインインしてコメントする。

カテゴリ

ヘルプ センター および File ExchangeCreating, Deleting, and Querying Graphics Objects についてさらに検索

製品

リリース

R2021b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by