Inpainting pixels between regions with nearest color in MATLAB - matlab

Is there an efficient way to fill in pixels with a value of zero between pixels with non-zero values with the nearest non-zero value, while leaving the rest of pixels at zero untouched?
To clarify, I am looking to inpaint those pixels whose closest distance to a non-zero pixel is lower than a given value (e.g. 4 pixels).
The image is initially represented as a matrix of uint32 integers.
In the example above, all the thin cracks between the colored regions should be filled with the surrounding color, while large black regions should remain the same (i.e. the routine should inpaint the pixels between the colored regions).
I imagine there is a way to do this via interpolation. In either case, I am looking for a relatively efficient solution.

Given an input matrix A:
b = imclose(A==0,ones(3,3)) %only the big zero regions
c = imdilate(A,ones(3,3)) %inpainting all neighboring pixels
d = zeros(size(A));
d(b==0) = c(b==0); %copy the inpainting only in places where there are no big regions
I haven't tested it, so there may be some problems with the code. (if you made changes to the code to make it work please edit my answer)

Related

Area integral invariant computation

Area integral invariant is a type of signature used in image processing. Does anyone know the algorithm for the computation of AII?
i.e. I want to calculate the area enclosed by a boundary and the intersected circle...
the boundary is not a curve with a equation but from a arbitrary profile. The image below is just a schematic drawing. The real boundary can be much more complex with the enclosed area in various positions of the boundary, i.e. top, bottom, left side...
The red area. I am using MATLAB and the image is mostly binary ones.
If you know the equation of the circle and the line then its quite easy, if you are doing this in an image.
Select the pixels that are inside the circle (easily done with the equation of the circle). If you need to compute the AII as a ratio, then count the pixels you have.
Separate the pixels above and below the line. You can do this easily if you know the equation of the line, or the value of the line in each column. Go column by column and discard the pixels that are above the value of the line. Count the result.
That's it! If you want the AII without a ratio, then the number of pixels in 2 is the result. If you want it as a ratio, divide the number of pixels of 2 by the number of pixels of 1.
If you only have the image and no equations, you can still select all the pixels you want by giving your algorithm one pixel in the area you want to calculate and then recusivly check all neighbors and add them to you area, if they are white. When you are done, just count the pixels you have. The result is in some sense the are of the region you wanted.

How to make a heat map on top of worldmap using hist3 in MATLAB?

My x-axis is latitudes, y-axis is longitudes, and z-axis is the hist3 of the two. It is given by: z=hist3(location(:,1:2),[180,360]), where location(:,1) is the latitude column, and location(:,2) is the longitude column.
What I now want is, instead of plotting on a self-created XY plane, I want to plot the same on a worldmap. And instead of representing the frequency of each latitude-longitude pair with the height of the bars of hist3, I want to represent the frequency of each location by a heat map on top of the world map, corresponding to each latitude-longitude pair's frequency on the dataset. I have been searching a lot for this, but have not found much help. How to do this? I could only plot the skeleton of the worldmap like this:
worldmap world
load geoid
geoshow(geoid, geoidrefvec, 'DisplayType', 'texturemap');
load coast
geoshow(lat, long)
I don't know what the colour is being produced based on.
Additionally, if possible, I would also like to know how to plot the hist3 on a 3D map of the world (or globe), where each bar of the hist3 would correspond to the frequency of each location (i.e., each latitude-longitude pair). Thank you.
The hist3 documentation, which you can find here hist3, says:
Color the bars based on the frequency of the observations, i.e. according to the height of the bars. set(get(gca,'child'),'FaceColor','interp','CDataMode','auto');
If that's not what you need, you might wanna try it with colormap. More info about it here colormap. I haven't tried using colormap on histograms directly, so If colormap doesn't help, then you can try creating a new matrix manually which will have values in colors instead of the Z values the histogram originally had.
To do that, you need to first calculate the maximum Z value with:
maxZ=max(Z);
Then, you need to calculate how much of the colors should overlap. For example, if you use RGB system and you assign Blue for the lowest values of the histogram, then Green for the middle and Red for the High, and the green starts after the Blue with no overlap, than it will look artificial. So, if you decide that you will have, for example overlapping of 10 values, than, having in mind that every R, G and B component of the RGB color images have 255 values (8 bits) and 10 of each overlap with the former, that means that you will have 255 values (from the Blue) + 245 values (From the Green, which is 255 - 10 since 10 of the Green overlap with those of the Blue) + 245 (From the Red, with the same comment as for the Green), which is total amount of 745 values that you can assign to the new colored Histogram.
If 745 > maxZ there is no logic for you to map the new Z with more than maxZ values. Then you can calculate the number of overlaping values in this manner:
if 745 > maxZ
overlap=floor(255- (maxZ-255)/2)
end
At this point you have 10 overlapping values (or more if you still think that it doesn't looks good) if the maximum value of the Z is bigger than the total amount of values you are trying to assign to the new Z, or overlap overlapping values, if the maximum of Z is smaller.
When you have this two numbers (i.e. 745 and maxZ), you can write the following code so you can create the newZ.
First you need to specify that newZ is of the same size as Z. You can achieve that by creating a zero matrix with the same size as Z, but having in mind that in order to be in color, it has to have an additional dimension, which will specify the three color components (if you are working with RGB).
This can be achieved in the following manner:
newZ=zeros(size(Z),3)
The number 3 is here, as I said, so you would be able to give color to the new histogram.
Now you need to calculate the step (this is needed only if maxZ > The number of colors you wish to assign). The step can be calculated as:
stepZ=maxZ/Total_Number_of_Colors
If maxZ is, for example 2000 and Total_Number_of_Colors is (With 10 overlaping colours) 745, then stepZ=2.6845637583892617449664429530201. You will also need a counter so you would know what color you would assign to the new matrix. You can initialize it here:
count=0;
Now, finally the assignment is as follows:
For i=1:stepZ:maxZ
count=count+1;
If count>245
NewZ(Z==stepz,3)=count;
elseif count>245 && count<256
NewZ(Z==stepz,3)=count;
NewZ(Z==stepz,2)=count-245;
elseif count>255
NewZ(Z==stepz,2)=count-245;
elseif count>500 && count<511
NewZ(Z==stepz,2)=count-245;
NewZ(Z==stepz,1)=count-500;
else
NewZ(Z==stepz,1)=count-500;
end
end
At this point you have colored your histogram. Note that you can manually color it in different colors than red, green and blue (even if you are working in RGB), but it would be a bit harder, so if you don't like the colors you can experiment with the last bit of code (the one with the for loops), or check the internet of some other automatic way to color your newZ matrix.
Now, how do you think to superimpose this matrix (histogram) over your map? Do you want only the black lines to be shown over the colored histogram? If that's the case, than it can be achieved by resampling the NewZ matrix (the colored histogram) with the same precision as the map. For example, if the map is of size MxN, then the histogram needs to be adjusted to that size. If, on the other hand, their sizes are the same, then you can directly continue to the next part.
Your job is to find all pixels that have black in the map. Since the map is not binary (blacks and whites), it will be a bit more harder, but still achievable. You need to find a satisfactory threshold for the three components. All the lines under this threshold should be the black lines that are shown on the map. You can test these values with imshow(worldmap) and checking the values of the black lines you wish to preserve (borders and land edges, for example) by pointing the cross tool on the top of the figure, in the tools bar on every pixel which is of interest.
You don't need to test all black lines that you wish to preserve. You just need to have some basic info about what values the threshold should have. Then you continue with the rest of the code and if you don't like the result so much, you just adjust the threshold in some trial and error manner. When you have figured that this threshold is, for example, (40, 30, 60) for all of the RGB values of the map that you wish to preserve (have in mind that only values that are between (0,0,0) and (40,30,60) will be kept this way, all others will be erased), then you can add the black lines with the following few commands:
for i = 1:size(worldmap,1)
for j = 1:size(worldmap,2)
if worldmap(i,j,1)<40 && worldmap(i,j,2)<30 && worldmap(i,j,3)<60
newZ(i,j,:)=worldmap(i,j,:)
end
end
I want to note that I haven't tested this code, since I don't have Matlab near me atm, so It can have few errors, but those should be easily debugable.
Hopes this is what you need,
Cheers!

Region merging by using superpixels

I implemented SLIC algorithm to find labels and I obtained the labels. I would like to compute a color feature vector that contains the average of the color features for each region. For each pair of neighboring regions, if the Euclidean distance between their feature vectors is less than a threshold, I will merge the two regions. I will do this for all pairs of neighboring regions. Then, I will repeat steps until no pair of regions can be merged. However, I don't know how to implement those steps.
there are a few choices for your color features, and they really depend on your colorspace, and what information you are looking for.
If your objective is to find objects that are the same color (invariant to lighting) I would strongly suggest the hsv colorspace you convert your regular rgb image using rgb2hsv the HSV colorspace has three channels (just like RGB) which are channel 1 = H = Hue = the color, channel 2 = S = Saturation = how vivid the color is, channel 3 = V = brightness Value = how bright a color is. all values are between 0 and 1. again if you wanted to find colors invariant of lighting, your feature would simply be the Hue channel. One thing to not about the hue channel is it is actually cyclic so 0 and 1 are actually the same (red). so your distance would have to wrap around. for instance pixel A has h=.7 pixel B has H=.3 pixel C has H=.01. which is closer to pixel A? you would immediately guess pixel B since delta_H=.4 but actually delta_H for a and c is only 0.31
If you are interested in more than just the simplistic color model by hue other choices are YCbCr, YUV (most people just use YCbCr since there is no TRUE YUV in matlab), CIE (also not completely native to matlab but it is supported as in this example). each of these represent the image brightness in the first channel. and the colors are represented by the last 2 channels. Using the last two channels, you could easily plot colors on a 2d cartesian plane, with one axis being channel2 and the other being channel 3 something like this (this example is specifically YCbCr colorspace)
and the similarity measure could be the euclidean distance between two colors
Im guessing your overall goal is some kind of compression. So what I would do is simply replace pixel values. So if pixel A and B are similar, then make the value of pixel B = pixel A. This means that every iteration you are reducing the total number of different colors in the image. Whereas with averages, you are still maintaining lots of different colors. think of it this way
replace
1. iteration 1, pixel A=x B=x+delta, and they are close enough so you say A=B=x
2. iteration 2, pixel B=x, C=x-delta, they are close so you say B=C=x
3. at this point you have A=B=C=x so there is a reduction in the number of colors from 3 to 1
average
1. iteration 1, pixel A=x B=x+delta, they are close so now A=B=x+.5delta
2. iteration 2, pixel B=x+.5delta, C=x-delta, they are so now B
3. at this point you have A=B=C=x so there is a reduction in the number of colors from 3 to 1

How to determine Boundary Cut Utilization MATLAB?

Working on 2D Rectangular Nesting. Need to find the utilization percentage of the material. Assuming i have the length, breadth, left-bottom position of each rectangle. What is the best way to determine the Boundary-Cut Utilization?
Objective:- To find the AREA under the RED Line.
Sample images attached to depict what i have done and what i need.
What i have done
what i need
Another Example image of rectangles packed with allowance
If you're interested in determining the total "area" underneath the red line, one suggestion I have is if you have access to the Image Processing Toolbox, simply create a binary image where we draw all of the rectangles on the image at once, fill all of the holes, then to determine the area, just determine the total sum of all of the binary "pixels" in the image. You said you have the (x,y) positions of the bottom-left corner of each rectangle, as well as the width and height of each rectangle. To make this compatible in an image context, the y axis is usually flipped so that the top-left corner of the space is the origin instead of the bottom-left. However, this shouldn't affect our analysis as we are simply reflecting the whole 2D space downwards.
Therefore, I would start with a blank image that is the same size as the grid you are dealing with, then writing a loop that simply sets a rectangular grid of coordinates to true for each rectangle you have. After, use imfill to fill in any of the holes in the image, then calculate the total sum of the pixels to get the area. The definition of a hole in an image processing context is any black pixels that are completely surrounded by white pixels. Therefore, should we have gaps that are surrounded by white pixels, these will get filled in with white.
Therefore, assuming that we have four separate variables of x, y, width and height that are N elements long, where N is the number of rectangles you have, do something like this:
N = numel(x); %// Determine total number of rectangles
rows = 100; cols = 200; %// Define dimensions of grid here
im = false(rows, cols); %// Declare blank image
%// For each rectangle we have...
for idx = 1 : N
%// Set interior of rectangle at location all to true
im(y(idx)+1:y(idx)+height(idx), x(idx)+1:x(idx)+width(idx)) = true;
end
%// Fill in the holes
im_filled = imfill(im, 'holes');
%// Determine total area
ar = sum(im_filled(:));
The indexing in the for loop:
im(y(idx)+1:y(idx)+height(idx), x(idx)+1:x(idx)+width(idx)) = true;
Is a bit tricky to deal with. Bear in mind that I'm assuming that y accesses the rows of the image and x accesses the columns. I'm also assuming that x and y are 0-based, so the origin is at (0,0). Because we access arrays and matrices in MATLAB starting at 1, we need to offset the coordinates by 1. Now, the beginning index for the row starts from y(idx)+1. We end at y(idx) + height(idx) because we technically start at y(idx)+1 but then we need to go up to height(idx) but then we also subtract by 1 as your coordinates begin at 0. Take for example a line with the width of 20, from x = 0 to x = 19. This width is 20, but we draw from 0, up to 20-1 which is 19. Because of the indexing starting at 1 for MATLAB, and the subtraction of 1 due to the 0 indexing, the +1 and -1 cancel, which is why we are just left with y(idx) + height(idx). The same can be said with the x coordinate and the width.
Once we draw all of the rectangles in the image, we use imfill to fill up the holes, then we can sum up the total area by just unrolling the whole image into a single vector and invoking sum. This should (hopefully) get what you need.
Now, if you want to find the area without the filled in holes (I suspect this is what you actually need), then you can skip the imfill step. Simply apply the sum on the im, instead of im_filled, and so:
ar = sum(im(:));
This will sum up all of the "white" pixels in the image, which is effectively the area. I'm not sure what you're actually after, so use one or the other depending on your needs.
Boundary-Cut Area without using Image Processing Toolbox.
The Detailed question description and answer could be found here
This solution is applicable only to Rectangular parts.

how to find the center of the mandelbrot set

is it possible to find the center of the big black spot(the area which with the set?)
I've tried to loop through all points which are in the set, sum their locationד and eventually divided by the num of points which are in the set.
it didn't work as expected because the the set isn't formed, e.g its not a perfect sphere or a square therefore the center always changes. is there another way of finding the center?
thanks!
Look for centers of mandelbrot set hyperbolic components
http://fraktal.republika.pl/eigensolve.html
That shape is a perfect cardioid (no other similar shapes in the Mandelbrot set are perfect cardioids, they are somewhat distorted).
Check Wikipedia, you'll find the equation for calculating the cardioid itself: http://en.wikipedia.org/wiki/Cardioid
Note, however that at the borders of the Mandelbrot map (where the black and non-black area meets) deciding whether a point belongs to the map or not, heavily depends on how many times you iterate z = z^2 + c. If you iterate it 50 times, the main cardioid will be smaller than if you iterate it 500 times because with 500 iteration more points at the border will go to infinity.