Remove shadow under image - matlab

I have used the following code to obtain a border of the image and also remove the shadow under the image.The image is a grayscale image.
The code is:
x = imread('image.jpg');
sobel_h = [-1 0 1;-2 0 2;-1 0 1];
sobel_v = [-1 0 1;-2 0 2;-1 0 1]';
x_sobel_h = conv2(x,sobel_h,'same');
x_sobel_v = conv2(x,sobel_v,'same');
x_sobel_c = sqrt((x_sobel_h).^2+(x_sobel_v).^2);
x_sobel_c=uint8(x_sobel_c);
figure,imshow(x_sobel_c);
z=x_sobel_c;
z(z~=0 & z<=150)=0;
z(z>0)=255;
figure,imshow(z);
I found this code on Matlab File Exchange.It is simple and works well with some images but the shadow remains in some images.
The shadow can be removed if I change z<=150 to a higher value.But depending on the image, this value needs to be changed.Does anyone know some other thresholding method to remove the shadow in different images? If anyone can point me to any kind of reference material, I would be grateful.Thank you

As mentioned in the comments, there will be no magic bullet for removing the shadows.
The closest you will probably be able to come is to use a dynamic method to determine the optimal threshold for each image. For example, Otsu's method is implemented in MATLAB, through the commands graythresh and multithresh (the former defines one threshold to divide the image into 2 classes, the latter allows you to specify the number of thresholds).

Related

Strange shading behaviour with normal maps in UE4

I've been having some very strange lighting behaviour in Unreal 4. In short, here's what I mean:
Fig 1, First, without any normal mapping on the bricks.
Fig 2, Now with a normal map applied, generated based on the same black-and-white brick texture.
Fig 3, The base pixel normals of the objects in question.
Fig 4, The generated normals which get applied.
Fig 5, The material node setup which produces the issue, as shown in Fig 2
As you can see, the issue occurs when using the generated HeightToNormalSmooth node. As shown, this is not an issue relating to object normals (see Fig 3) or to a badly exported normal map (as there isn't one in the traditional sense), nor is it an issue with the HeightToNormalSmooth node itself (Fig 4 shows that it generates the correct bump normals).
To be clear, the issue here is the fact that using a normal texture at all (this issue occurs across all my materials) causes the positive Y facing faces of an object to turn completely black (or it seems, to become purely reflections-based, as increasing roughness on the material causes the black faces to become less 'shiny' looking).
This is really strange, I've tested with multiple different skylight setups, sun directions, and yet this always happens (even when lit directly), but only on +Y aligned faces.
If anyone can offer insight that would be greatly appreciated.
You're subtracting what looks like 1 from the input that then goes into multiply by 1, if I'm correct. This will, in most cases, make any image return black. This is because in UE4 and many other programs, colors in an image are determined by decimals of Red Green and Blue. These decimals fall in a range of 0 to 1. This means if I wanted to make red, I could use these values- R = 1 G = 0 B = 0. This matters because if R = 0 G = 0 B = 0, the result is black. When you use a multiply node in your example, what you are doing is having UE4 take each pixel of the image you fed into the node (if it was white, R = 1 G = 1 B = 1) and multiply its R, G, and B values by that number. Since zero multiplied by a number equals zero, all the pixels in the image are being set to have values of R = 0, G = 0, and B = 0. thus, all zeros, and you get black.
I also noticed you then multiplied it by one, which in most cases won't do a whole lot, since you're just multiplying the input by 1. If your input is 0, (black), multiplying it by one won't change it, cause 0 * 1 still equals 0.
To fix your issue, try changing the value you subtract from your input to be something smaller than one, say a decimal, such as 0.6 or 0.5
So I've discovered why this was an issue. Turns out there's a little option in the material settings called 'Tangent Space Normal'. This is on by default ('for convenience'), disabling this appears to completely fix the issue with the generated normal maps produced by HeightToNormalSmooth.

Subtract background in image with Matlab

I have a list of images that i expect to have uneven illumination across the x axis only. The background estimation/model will be calculated in advance but only its shape will be given (so i will not have an empty background image that i can just subtract), I will just have the form/shape of it (for example linear).
Is there a way to subtract the background and get an even illumination of the image with just knowing its shape (and without having an actual background image)? I have attached an image from the Matlab library that was created using a linear background (background=-3*x+0.5). Can someone show me how to go from this example to the original image with just using the background shape?
I am also including the original image.
If you have the shape, and the conditions you state are correct, then you have the full background information. It is, however, not possible to undo the clipping that happened (where the image has values 255, you don't know what the original value was).
This is how you would create a background image given the shape:
img = imread('https://i.stack.imgur.com/0j2Gi.jpg');
img = img(27:284,91:370); % OP posted a screen shot? What is this margin?
x = 0:size(img,2)-1;
background = 0.3*x+0.5;
background = repmat(background,size(img,1),1);
imshow(img-background)
The results looks not exactly like the original image, but most of that can be explained by the clipping.
I replaced your -3*x+0.5 with 0.3*x+0.5 because the -3 makes no sense, and 0.3 makes it so that the background values remain in a meaningful range.
If, on the other hand, you are asking about fitting the linear model to the image data and estimating the exact background to subtract, then the problem is a bit more difficult, but not impossible. You can, for example, make an assumption about intensity uniformity across the x-axis if the illumination had been uniform across the image. You can then take the mean intensity along the x-axis and fit your model to it:
meanintensity = mean(img,1)';
plot(m)
X = [ones(length(meanintensity),1),(0:length(meanintensity)-1)']; % meanintensity = X*params
params = X\meanintensity;
hold on, plot(X*params)
background = X*params;
background = repmat(background',size(img,1),1);
imshow(img-background)

Filling the gaps in a binary image

I have found a couple areas referring to filling of gaps in binary images in matlab, however I am still struggling. I have written the following code but I cannot get it to work. Here is my binary image:
.
However, what I'm trying to achieve is the following
.
Does anyone know how to do this? I have been trying using imfill but I know I think I need to define boundaries also with the bwlabel function but I dont know how. Any help would be greatly appreciated.
%%Blade_Image_Processing
clc;
clear;
%%Video file information
obj = VideoReader('T9_720p;60p_60mm_f4.MOV');
% Sampling rate - Frames per second
fps = get(obj, 'FrameRate');
dt = 1/fps;
% ----- find image info -----
file_info = get(obj);
image_width = file_info.Width;
image_height = file_info.Height;
% Desired image size
x_range = 1:image_height;
y_range = 1:image_width;
szx = length(x_range);
szy = length(y_range);
%%Get grayscale image
grayscaleimg1 = rgb2gray(read(obj,36));
grayscaleimg = imadjust(grayscaleimg1);
diff_im = medfilt2(grayscaleimg, [3 3]);
t1=60;
t2=170;
range=(diff_im > t1 & diff_im <= t2);
diff_im (range)=255;
diff_im (~range)=0;
% Remove all those pixels less than 300px
diff_im = bwareaopen(diff_im,2000);
%imshow(diff_im)
%imhist(grayscaleimg)
%Fill gaps in binary image
BW2 = imfill(diff_im,'holes');
There are two main problems: desired object has no readily usable distinguishing features, and it touches other object. Second problem could be perhaps cleared with morphological opening/closing (touching object is thin, desired object not, is this always the case?), but first problem remains. If your object touched edge but others didn't or vice versa, you could do something with imfill and subtractions. As it is now, MAYBE something like this would work:
With opening/closing remove connection, so your object is disjoint.
With imfill, remove what is left of this thin horizontal thing.
Then, you can bwlabel and remove everything that touches sides or bottom of the image - in shown case that would leave only your object.
Exact solution depends heavily on what additional constrains are there for your pictures. I believe it is not a one-shot, rather you have more of those pictures and want to correctly find objects on all? You have to check what holds for all pictures, such as if object always touches only something thin or if it always touches only upper edge etc.

VL_SLIC MATLAB Output for VL_FEAT

I am using the VL_SLIC function in MATLAB and I am following the tutorial for the function here: http://www.vlfeat.org/overview/slic.html
This is the code I have written so far:
im = imread('slic_image.jpg');
regionSize = 10 ;
regularizer = 10;
vl_setup;
segments = vl_slic(single(im), regionSize, regularizer);
imshow(segments);
I just get a black image and I am not able to see the segmented image with the superpixels. Is there a way that I can view the result as shown in the webpage?
The reason why is because segments is actually a map that tells you which regions of your image are superpixels. If a pixel in this map belongs to ID k, this means that this pixel belongs to superpixel k. Also, the map is of type uint32 and so when you try doing imshow(segments); it really doesn't show anything meaningful. For that image that is seen on the website, there are 1023 segments given your selected parameters. As such, the map spans from 0 to 1023. If want to see what the segments look like, you could do imshow(segments,[]);. What this will do is that the region with the ID of 1023 will get mapped to white, while the pixels that don't belong to any superpixel region (ID of 0), gets mapped to black. You would actually get something like this:
Not very meaningful! Now, to get what you see on the webpage, you're going to have to do a bit more work. From what I know, VLFeat doesn't have built-in functionality that shows you the results like what is seen on their webpage. As such, you will have to write code to do it yourself. You can do this by following these steps:
Create a map that is true that is the same size as the image
For each superpixel region k:
Create another map that marks true for any pixel belonging to the region k, and false otherwise.
Find the perimeter of this region.
Set these perimeter pixels to false in the map created in Step #1
Repeat Step #2 until we have finished going through all of the regions.
Use this map to mask out all of the pixels in the original image to get what you see in the website.
Let's go through that code now. Below is the setup that you have established:
vl_setup;
im = imread('slic_image.jpg');
regionSize = 10 ;
regularizer = 10 ;
segments = vl_slic(single(im), regionSize, regularizer);
Now let's go through that algorithm that I just mentioned:
perim = true(size(im,1), size(im,2));
for k = 1 : max(segments(:))
regionK = segments == k;
perimK = bwperim(regionK, 8);
perim(perimK) = false;
end
perim = uint8(cat(3,perim,perim,perim));
finalImage = im .* perim;
imshow(finalImage);
We thus get:
Bear in mind that this is not exactly the same as what you get on the website. I simply went to the website and saved that image, then proceeded with the code I just showed you. This is probably because the slic_image.jpg image is not the exact original that was given in their example. There seems to be superpixels in areas where there are some bad quantization artifacts. Also, I'm using a relatively old version of VLFeat - Version 0.9.16. There may have been improvements to the algorithm since then, so I may not be using the most up to date version. In any case, this is something for you that you can start with.
Hope this helps!
I found these lines in vl_demo_slic.m may be useful.
segments = vl_slic(im, regionSize, regularizer, 'verbose') ;
% overaly segmentation
[sx,sy]=vl_grad(double(segments), 'type', 'forward') ;
s = find(sx | sy) ;
imp = im ;
imp([s s+numel(im(:,:,1)) s+2*numel(im(:,:,1))]) = 0 ;
It generates edges from the gradient of the superpixel map (segments).
While I want to take nothing away from ~ rayryeng's ~ beautiful answer.
This could also help.
http://www.vlfeat.org/matlab/demo/vl_demo_slic.html
Available in: toolbox/demo

MATLAB colormapping issue with value 0

I already searched the web and stack overflow for answers to this (seemingly simple) question, however could't find the answer:
I am in the progress of writing a cellular automaton in MATLAB. I am using an n*m matrix with values between 0 and 15, from which I make an image using a colormap with 5 grey values (between 0 and 1). See the following code snippet to clarify this:
WIDTH = 100;
HEIGHT = 100;
fields = randi(16,HEIGHT,WIDTH)-1;
% here the grey values 0, 0.25, 0.5, 0.75 and 1 are mapped to the values 1 to 16
cmRow = [1;0.75;0.75;0.5;0.75;0.5;0.5;0.25;0.75;0.5;0.5;0.25;0.5;0.25;0.25;0];
specialGray = [cmRow, cmRow, cmRow];
colormap(specialGray);
image(fields)
Well my problem is, that there is no 0th row in the colormap that MATLAB would use, if a value 0 occurs. As a result, there is always one color missing.
Just using values from 1 to 16 instead of from 0 to 15 is unfortunately not an option, as I heavily rely on these values later in the script.
Is there something obvious, I am missing? Do you have any ideas how to tackle this issue?
Thank you very much!
Best regards,
René
The image function knows two type of color mapping: direct' (the default) and 'scaled'. If you use 'scaled', you can set the scale for the color with thecaxis` function. Thus, the following code should do the trick (but you can of course also transform the values as suggested by Oleg):
image(fields,'CDataMapping','scaled');
colormap(specialGray);
caxis([0 15]);