How to replace specific areas in matlab figure by zero?

I have a matlab figure file as shown below. I have extracted this image into a matrix named 'figmat' using the code
openfig('newmeas.fig');
figmat=get(get(gca,'Children'),'CData');
1) How to know which rows and columns in 'figmat' correspond to this bottom yellow line?
2) How to replace the bottom bright yellow line with zero values in 'figmat'?

 Accepted Answer

You can see that the axes increase in both directions away from the bottom left corner. In MATLAB, that is the case when the axes XDir and YDir properties are both set to 'normal'. When they are both set to normal, then the lower left corner of the display corresponds to CData(1,1,:), and the upper left corner corresponds to CData(end,1,:); the lower right corresponds to CData(1,end,:) . The bright yellow line therefore corresponds to rows near the beginning of the CData.
It is not clear to me that the line corresponds to CData(6,:,:) only; there might be a couple of values in the row before or after that which have the same color.
I would suggest trying
f = openfig('newmeas.fig');
obj = findobj(f, 'hasprop', 'CData');
figmat = get(obj, 'CData');
fm2 = figmat;
fm2(6,:,:) = 0;
set(obj, 'CData', fm2);

11 Comments

Thanks for the answer. I had some more clarifications. The extracted image size in matrix is 2048x88 (2048 rows and 88 columns). Among so many rows how does one find out, till what row exactly from the beginning values the yellow band extends? (Because I want to set the complete yellow band at the bottom to zero)
Is this an RGB image, like your extracted image is 3-D, like 2048x88x3, (which I doubt), OR is it an indexed image, like a 2-D image with a colormap applied (which I suspect is likely)?
Try taking the vertical profile and looking for a peak or valley:
verticalProfile = mean(yourImage, 2);
It's best to work with your original image, before you put it into an axes and saved it as a .fig file. Even more so if you applied a colormap to it because CData will be the RGB data but unless you have the colormap you won't be able to get the original values back again.
Image Analyst, this is a 2D image with colormap applied as you said and not an RGB. The pcolor plot is a matlab.fig file generated after plotting measurement values( It is not JPEG, PNG, TIFF or any other format).
In the matrix of the matlab.fig are power magnitudes which are mapped to the colors for display in the pcolor plot. From the peak I just get a single value. How to determine range of values in the matrix corresponding to some colors in the image and replace them with zero?
For example:How to determine all rows in the verticalProfile matrix corresponding to the yellow band or if I choose a different color map say bottom red strip instead of yellow.
When you pcolor(), the CData that get saved is the original data, not the RGB version of it. You need to examine the axes CLimMode and CLim and https://www.mathworks.com/help/matlab/ref/caxis.html and the surface CDataMapping to determine how the axes and surface are set to map data ranges
Likely you will find that CLimMode = 'auto', and CDataMapping = 'scaled' and CLim = [min(YourData(:)), max(YourData(:))] . In that combination, the smallest actual data value will map into the first color in your color map, and the largest actual data value will map into the last color in your color map, and everything else will map linearly.
probeRGB = [255,255,102]; %either as 0-255 or 0-1
if any(probeRGB > 1); probeRGB = double(probeRGB) / 255; end
f = openfig('newmeas.fig');
obj = findobj(f, 'hasprop', 'CData'); %find the surface
ax = ancestor(obj, 'axes'); %find its axes
cmap = colormap(ax); %retrieve the colormap
numcol = size(cmap,1); %how many colors in the map?
%find index of closest matching color
cdist = sum((cmap - repmat(probeRGB, numcol, 1)).^2,2);
[~, cidx] = min(cdist);
%retrieve stored data from pcolor
figmat = double(get(obj, 'CData'));
%map data to color index
clim = get(ax, 'CLim'); %find color range mapping
colnum = uint16( floor( (figmat - clim(1)) ./ (clim(2) - clim(1)) * (numcol-1) ) ); %do not assume there are at most 256 colors, just in case
At this point, the places at which colnum == cidx are the ones where the matching color is as close as possible to the probeRGB that you gave. You can now, for example,
new_colnum = colnum;
new_colnum(new_colnum == cidx) = 0; %replace with lowest color
image( ind2rgb(newcolnum, cmap) );
set(gca, 'YDir', 'normal'); %image() defaults to YDir reverse
By default, pcolor puts black edges around each pixel, and the above image() does not do that. On the other hand, we can see that you turned that off in what you posted.
There is an important difference between how I process the data here, and how pcolor processes the data for display. I process the CData as if each array element is the center of a blob of color, like image() and imagesc() does. pcolor() on the other hand processes each array element as if it is the vertices of a patch whose average center value needs to be interpolated and the average used; because of that, the number of rows and columns displayed for pcolor is one fewer than the number of rows and columns in the data.
If it is important that the vertex-interpolation behavior be preserved, then let us know.
I would suggest, however, that you consider switching away from using pcolor unless your data is positioned parametrically. If you are passing x and y positions to pcolor and those are not a strict equi-spaced rectilinear grid, then you should continue to use pcolor; if you are not passing x and y or if they are on a strict equi-spaced rectilinear grid, then I would recommend you switch to imagesc() or imshow().
If you are passing x and y positions to pcolor then the sample new output will not work, and you should instead use
newfigmat = figmat;
newfigmat(colnum == cidx) = clim(1); %replace with lowest color
set(obj, 'CData', newfigmat);
I agree with Walter. Stop using pcolor or any other display routine and then trying to get the data back out of it. You have the original data so just use that directly. Please attach it in a .mat file. Save the data to a .mat file with save().
@ Walter, Thanks for the excellent reply. Since I'm new to matlab, it took me a while to understand the points and try. I get the following plot with blue streaks (0 value) at the bottom after following your instructions where only few values are replaced to zero. How to make the entire bottom yellow band to zero values?
And an other question I have is the how to preserve the original pixel values? The image gets somewhat pixelated after doing the above processing.
Try the second version,
newfigmat = figmat;
newfigmat(colnum == cidx) = clim(1); %replace with lowest color
set(obj, 'CData', newfigmat);
The reason for the pixelation in the first version is that it turns out that you have many more pixels high than your axes window is set up for, and you have many fewer pixels wide than your axes window is set up for (only about 90.) You are getting some compression artifacts in one direction, and you are getting expansion artifacts in the other direction. If you have a sufficiently new MATLAB you could try ensuring that the figure has anti-aliasing enabled, but it probably would not be enough.
pcolor does not have that stretching issue because pcolor creates surfaces that can be multiple pixels wide and it colors those smoothly.
With regards to only a few pixels being matched:
The image you posted is .jpg, which makes it difficult to tell what your original pixel values were (because JPEG is lossy.) Based on what I see in examining, it appears to me that your bright yellow band might perhaps be a number of close colors rather than being just one color.
You should bring up your surface and then go to the top of the image and click on the magnifying + glass, and zoom in near part of the yellow band. Then click on the data cursor tool (between the rotation tool and the paintbrush) and click in some places in the yellow you want to eliminate and see if consistent RGB values are shown. If they are then you can code those in the probeRGB line. The actual index should be displayed as well since it is colormapped; you can use the actual index in place of trying to figure out what the index is by looking for the smallest color difference the way I do.
If it turns out that you have a range of yellows, then frankly the easiest approach would be to go back to the original data and start doing
mask = YourData >= lowbound & YourData <= highbound;
datacopy = YourData;
datacopy(mask) = 0;
and then pcolor datacopy instead of YourData . You would figure out appropriate lowbound and highbound by using the data cursor.
@Walter, thanks for the suggestions. I tried with few things and obtained the image as uploaded here where I could get some of the bottom rows to be valued to zero. But now an other question remains for me. The light blue color (cyan) sloped line you see approximately between the values 300 and 400 is a useful signal and the values from 200 and below (with the same color) are noise.
1) How to make only the noise part zero preserving the values of the useful signal?
2) Is there any way to extract portion of images as a matrix or identify in the original matrix which row/column corresponds to which part in the image?
Thanks for any assistance
"Is there any way to extract portion of images as a matrix or identify in the original matrix which row/column corresponds to which part in the image?"
With the plotting you have done, the x coordinate is the column number of the data, and the y coordinate is the row number of the data.
"How to make only the noise part zero preserving the values of the useful signal?"
You really need to go back to the original data instead of working with the drawn data.

Sign in to comment.

More Answers (0)

Categories

Find more on Images in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!