I want to change the backgroung color of image into transparent and then work with the pixels of it

4 views (last 30 days)
Is it possible to crop a part of the image automatically without drawing the circle or any other shape around it?
I already have the special shape (nearly a circle) and black backround color around it, but would like to only have the special shape part of it, which is mostly not black. (picture attached -> komplett_S1.jpg) Because I have to load different images, I can not only "draw" one shape and it fits every image, right?
At the moment I cut the picture to a "square" which has black spots at the corners of the picture which I want to cut too.
I am able to change the original colored image into grayscale, into binary image and then draw a circle around the biggest blob. The aim is, to "cut" this circle for the image in original color and grayscale too. (picture2) When changing the backgroungcolor of the picture there is no transparency which I wish to have and the edges are not clear as drawed by the circle in "Biggest Blob". (picture3 and picture4)
In my nex step I would like to sum the small dots inside the special shape (circle) which are brighter than a special value. All the black spots inside the red circle drawn should be deleted or better to say, summed up for another value (for example tfa).
But at first I want to "cut" and show the special shape (image cutted at the red circle in grayscale and original color) of the image. Is there any way for doing that?
The grayscale picture which I want to work with in the future should be shown at the top in the middle and the original image in the right top corner (picture5).
Many thanks for your help!
  2 Comments
DGM
DGM on 11 Apr 2024
Edited: DGM on 11 Apr 2024
For the purposes of processing, there is no need to crop or make anything transparent. Nothing in base MATLAB or IPT will handle an image with attached alpha data, so making a transparent image only creates a new problem.
Create a mask which describes the colored regions you want to analyze, (e.g. such that each region is represented by one blob). You can then count the blobs or find their average intensity or do whatever you want on them.
If you want to find information about interstitial spaces which may include gaps at the perimeter, perhaps you can consider the difference of the aforementioned mask and its convex hull.
What are the specific statistics that are needed? Blob count? Area? What is the appropriate brightness metric/threshold? Do green regions which aren't bright enough count as black regions?
Svenja Jetzinger
Svenja Jetzinger on 12 Apr 2024
Thank you very much.
First of all I need to count all the small blobs inside of the big circle. Second I only want to count the black spots inside of it.
The problem is, I haven't understood yet what values are needed to count all of those blobs with for loops. Are those values pixels or color (rgb) values?
The aim is to count those blobs with grayscale image with two for loops (rows and columns). Those green or darker gray areas count as black regions too. Because I haven't understood what values are needed I can't tell you some brightness metric or threshold values.

Sign in to comment.

Accepted Answer

DGM
DGM on 12 Apr 2024
I'm still confused as to what information is important, so I'm just going to throw out what I have in notes. This is in part based on @Image Analyst's first link, so you might want to read that first.
This tries to get a mask which has all the green regions (cells?) selected individually. There are a couple very dark cells which are missed, and there are a number of cells which are split by dark marks/cracks/scratches.
A big part of the challenge is dealing with the wide variation in local contrast. I decided to upsample the image so I had enough resolution to more reliably isolate the cells.
% the original image
rgbpict = imread('komplett_S1.jpg');
% a grayscale copy for analysis
% i don't know what grayscale metric is appropriate
% so i'm just going to use luma
lumapict = im2gray(rgbpict);
% a grayscale copy for segmentation
% V has more consistent contrast than Y here
valuepict = max(rgbpict,[],3);
% crop to the bounding box to reduce the image area
% and for the sake of symmetry
mk = imbinarize(valuepict);
mk = bwareafilt(mk,1);
mk = bwconvhull(mk);
mk = imdilate(mk,ones(5));
[hullmask yrange xrange] = crop2box(mk);
valuepict = valuepict(yrange,xrange);
lumapict = lumapict(yrange,xrange);
% resize so we have more resolution to work with when filtering
% this can help avoid bridges/breaks, since filters can only be integer-sized
upsamplefactor = 2;
valuepict = imresize(valuepict,upsamplefactor);
hullmask = imresize(hullmask,upsamplefactor);
lumapict = imresize(lumapict,upsamplefactor);
% try to make the local contrast uniformly adequate
flatpict = imflatfield(valuepict,5,hullmask);
flatpict = imadjust(flatpict,stretchlim(flatpict,0.05));
% try to get a crude mask representing the background
bgmask = imopen(flatpict,strel('disk',3,0));
bgmask = bgmask > 200;
bgmask = ~bwareaopen(~bgmask,25);
bgmask = ~imfill(bgmask,'holes');
This is the point at which the watershed segmentation starts to follow the article.
% get the distance map
D = -bwdist(bgmask);
% split blobs as shown in the blog article
regionmin = imextendedmin(D,2); % the basin minima (ideally one per cell)
D = imimposemin(D,regionmin);
ridgelines = watershed(D);
splitmask = ~bgmask;
splitmask(ridgelines == 0) = false;
% visualize the segmentation
segview = imfuse(regionmin,~bgmask);
imshow(segview,'border','tight')
set(gca,'xlim',[91 402],'ylim',[1243 1554]) % zoom in so it's visible on the forum
% view the finished mask
imshow(splitmask,'border','tight')
set(gca,'xlim',[91 402],'ylim',[1243 1554]) % zoom in so it's visible on the forum
Now that you have a mask where all the cells are separated from each other, you can continue to refine the mask if you want, or you can start using it to get information about the image. In this case, I'm just going to get the number of blobs (cells and cell fragments) in the mask, and the distribution of their average luma.
% at this point, you can count the blobs in the mask
% or you can get rid of small blobs (e.g. bwareaopen())
% get info about a grayscale image
% based on the regions defined in the mask
% i don't know what statistics are important
% so i'm just going to pick average gray level (i.e. mean luma)
S = regionprops(splitmask,lumapict,'meanintensity');
% the number of blobs
nblobs = numel(S)
nblobs = 5052
% do something with the region information
histogram(vertcat(S.MeanIntensity))
If you want to look at black regions (e.g. within the convex hull of the section, you can use the masks we've already created and then process them as is appropriate for your needs.
% maybe you want to look at large interstitial spaces or something
gapmask = hullmask & ~splitmask;
gapmaskopened = imopen(gapmask,strel('disk',9)); % maybe only look at thick parts
% visualize the opening of the gap mask
gmview = imfuse(gapmask,gapmaskopened);
imshow(gmview,'border','tight')
I don't know how much of that is useful to you. Note that I attached one of the ancillary functions that I used in this example.
  2 Comments
Svenja Jetzinger
Svenja Jetzinger on 12 Apr 2024
Edited: Svenja Jetzinger on 15 Apr 2024
Thank you so much!
I will need some days to analyse and understand your code.
But the questions I already have are:
  1. You count all the black blobs inside the circle, right?
  2. Is it possible to count the white blobs as well?
  3. And why do you use the value 200 in this code segment:
% try to get a crude mask representing the background
bgmask = imopen(flatpict,strel('disk',3,0));
bgmask = bgmask > 200;
bgmask = ~bwareaopen(~bgmask,25);
bgmask = ~imfill(bgmask,'holes');
=> What does this stand for? Is the 200 because of the 200 colormaps?
Is it possible to find this value automatically for every original picture I have? (Because when changing the value to 190 it works for the second original picture I sent you)
=> And what is the logical not (~) for?
4. Have you chosen the upsamplefactor of 2, because values higher than 1 enlarge the picture? But why have you chosen 2 instead of e.g. 5?
5. I tried the code based on the first link from @Image Analyst and didn't got the expected result (picture6). Your code helps me in this point very much! Thank you for that!
6. Is it possible to change dark gray values into white blobs too? What values are needed for that?
7. I have to analyse some other pictures with the same code. How to open it isn't the problem. But your code doesn't fully work for those. (I will show you in the next picture -> picture7 and attache one more original example picture). The aim is to load one individual original picture in jpg format and analyse (e.g. counting the blobs) this picture. But all the black spots from original picture changed each picture. So it's very important for me counting all of those black blobs and maybe some dark gray blobs, turned into black blobs too. (Hopefully you understand what I mean.)
Greetings
DGM
DGM on 16 Apr 2024
1: The dark blobs (for some definition of "dark blobs") can be counted by getting the number of connected groups in the gapmaskopened. That could be done using bwlabel():
[Labelarray nblobs] = bwlabel(gapmaskopened);
bwconncomp(),
CC = bwconncomp(gapmaskopened);
nblobs = CC.NumObjects
or regionprops()
S = regionprops(gapmaskopened,'area');
nblobs = numel(S)
Which one I use usually depends on what other things I'm also looking for. Usually I'm after properties, so if I'm going to use regionprops() anyway, I'll use that.
2: Same as #1, just use a different mask (i.e. splitmask). The same disclaimer applies regarding whether you want to do post-processing on the mask before counting.
3: The 200 is just the particular threshold value I chose to binarize the flattened image. That was just a manually picked value in uint8 scale (0-255). I'm not sure if using imbinarize() would do a good job of automatically picking this level. I generally don't trust it to work without any oversight, but it might require less oversight than a fixed threshold. You might try using it if you want more automation and find that a fixed threshold requires too much adjustment.
The inversions in the call to bwareaopen() are used because there is no corresponding function for area-based closing (i.e. removing holes with less than a specified area). The objective can be achieved by performing the inverse of the opening of the inverse of the mask.
The last inversion after the imfill() call is perhaps conceptually out of place, but it's necessary for the way the mask will be used in the call to bwdist(). We want D to be the distance from the background, so bgmask needs to be inverted.
4: I just chose 2 since It seemed adequate. Larger images just cost time and memory.
5: I have never had very good luck getting worry-free results from my attempts at watershed segmentation, so I can't fault anyone for losing hair over the challenge. I guess it's one of those things that require the kind of discretion that comes with experience I don't have.
6: What gets converted to white depends on the thresholds selected
bgmask = bgmask > 200;
... although the preprocessing steps (the flattening and opening) may also influence this.
The problem really is that from a strictly graylevel-based perspective, there are a lot of dim green cells which are dimmer than the gaps between bright green cells. It would be hard to include very dim green cells without bright green cells becoming so heavily connected that our subsequent attempts at watershed segmentation couldn't split them back apart. On the other hand, from the perspective of an extended local maximum, a lot of the dim green cells are barely maximal regions. They're surrounded by a only slightly darker perimeter which is in turn adjacent to a much more significant local maximum. So it's also hard to always get something like imextendedmas() to give us the dim cells without creating holes or subdividing bright cells. I tried to get it to pick up as much as I could, but I never could get it to pick up everything without risking the bright cells becoming grossly connected. There might be a smarter way to approach a problem like this, but I'm not exactly a pro.
7: Regarding counting blobs, that's #1&2, but as mentioned, you might need to adjust thresholds or other parameters as you go in order to make sure you're getting the segmentation that you hope to get. There may be some further post-processing that you can do using the generated masks, either to discard bright cells which are incomplete, or perhaps to extract portions of the "dark" mask which are in fact just dim green cells which didn't get counted.

Sign in to comment.

More Answers (1)

Image Analyst
Image Analyst on 11 Apr 2024

Products


Release

R2022a

Community Treasure Hunt

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

Start Hunting!