Edge linking in Matlab - matlab

I am trying to link the edges in images like the image below:
I've tried using dilation/erosion operations but the result isn't good. Is there any other way to link the edges?
Here is the original image:

The result you have might very well be good enough to apply the Hough transform to, which will identify your eight most important lines across the image.
I don't know if all your images are similar, but in the example you show it is easy to separate the gray lines from the green background. For example, the following code (using DIPimage, but easy to implement with other tools too) will distinguish the relatively bright gray from anything that is dark or colorful:
img = readim('https://i.stack.imgur.com/vmBiF.jpg');
img = colorspace(img,'hsv');
img = (0.5-img{2})*img{3}; % img{2} is the saturation channel, img{3} is the value (intensity) channel
img = clip(img); % set negative values to 0
Next, a Laplace of Gaussian filter (which is a line detector), some thresholding just above zero, and a selection of only the larger objects results in the detected lines:
img = -laplace(img,5); % LoG with sigma=5
img = img > 0.05; % 0.05 is just above 0
img = areaopening(img,1000); % remove objects smaller than 1000 pixels
Needless to say, this is a lot cheaper computationally than running a U-Net.

Related

How to group pixels into blobs in Matlab?

I have this image with white points on a dark background:
I want to group pixels that are close by into a single blob. In this image, that would mean that there will be two blobs in the image, one for the pixels at the top and one for the pixels at the bottom. Any pixels that are not too close to these two blobs must be changed into the background color (A threshold must be specified to choose which pixels fall into the blobs and which of them are too far). How do I go about this? Any Matlab function that can be used?
To group dots, one can simply smooth the image sufficiently to blur them together. The dots that are close together (with respect to the blur kernel size) will be merged, the dots that are further apart will not.
The best way to smooth the image is using a Gaussian filter. MATLAB implements this using the imgaussfilt function since 2015a. For older versions of MATLAB (or Octave, as I'm using here) you can use fspecial and imfilter instead. But you have to be careful because fspecial makes it really easy to create a kernel that is not at all a Gaussian kernel. This is the reason that that method is deprecated now, and the imgaussfilt function was created.
Here is some code that does this:
% Load image
img = imread('https://i.stack.imgur.com/NIcb9.png');
img = rgb2gray(img);
% Threshold to get dots
dots = img > 127; % doesn't matter, this case is trivial
% Group dots
% smooth = imgaussfilt(img,10); % This works for newer MATLABs
g = fspecial("gaussian",6*10+1,10);
smooth = imfilter(img,g,'replicate'); % I'm using Octave here, it doesn't yet implement imgaussfilt
% Find an appropriate threshold for dot density
regions = smooth > 80; % A smaller value makes for fewer isolated points
% Dots within regions
newDots = dots & regions;
To identify blobs that are within the same region, simply label the regions image, and multiply with the dots image:
% Label regions
regions = bwlabel(regions);
% Label dots within regions
newDots = regions .* dots;
% Display
imshow(label2rgb(newDots,'jet','k'))

Template matching

I am trying to detect elevators on floor plans in MATLAB. The code I have now is not detecting elevators, it is instead just pointing at the edges of the image. I am expecting to detect all the elevators on a floor plan. Elevators are represented by a square or rectangle with an x inside, similar to the template image. I have attached the template, image and a result screenshot.
Template image:
Image:
Results:
Code:
template= rgb2gray(imread('ele7.png'));
image = rgb2gray(imread('floorplan.jpg'));
%imshowpair(image,template,'montage')
c = normxcorr2(template,image);% perform cross-correlation
figure, surf(c), shading flat
[ypeak, xpeak] = find(c==max(c(:)));%peak of correlation
%Compute translation from max location in correlation matrix, =padding
yoffSet = ypeak-size(template,1);
xoffSet = xpeak-size(template,2);
%Display matched area
figure
hAx = axes;
imshow(image,'Parent', hAx);
imrect(hAx, [xoffSet+1, yoffSet+1, size(template,2), size(template,1)]);
To check if everything runs smoothly, you should plot the correlation:
figure, surf(c)
As mention by #cris-luengo , it's easy to fail with the sizes of the image and so on. However, I've seen that you followed the tutorial on https://es.mathworks.com/help/images/ref/normxcorr2.html . Since both images, already black and white images (or 2-colour images), normxcorr2 works well with rgb images (with textures and objects, etc...). Thus, I think that is not a correct approach to use normxcorr2.
An approach I would consider is look for branches. Using Matlab's help and bwmorph:
BW = imread('circles.png');
imshow(BW);
BW1 = bwmorph(BW,'skel',Inf);
You first skeletonize the image, then you can use any of the functions that displayed on bwmorph's help (https://es.mathworks.com/help/images/ref/bwmorph.html). In this case, I'd search for branch points, i.e. crosslinks. It is as simple as:
BW2 = bwmorph(BW1,'branchpoints');
branchPointsPixels = find(BW2 == 1);
The indices of the branch points pixels, will be where it finds an X. However, it can be any rotated X (or +, ...). So you'll find more points that you desire, you would need to filter the points in order to get what you want.

comparing images pixel by pixel

I am working on some images. I am given an abc.tif image ( color image) . I read it as follows:
Mat test_image=imread("abc.tif",IMREAD_UNCHANGED);
I perform some operations on it and convert it into some binary image (using threshold) containing only two values 0 and 255 which are stored in img image where img is created as following:
Mat img(584,565,CV_8UC1); %//(so now img contains only 0 and 255)
I save this image using imwrite("myimage.jpg",img);
I want to compare the myimage.jpg image with another binary image manual.gif pixel by pixel to check whether one image is duplicate of another but as you can notice the problem is OpenCv doesnot support .gif format so I need to convert it into .jpg and because of that the image changes and now both the images will be concluded as different images may be even though they are same. What to do now?
Actually I am working on retinal blood vessel segmentation and these images are found in the DRIVE database.
I am given these images. Original image:
I perform some operations on it and extract blood vessels from it and then create a binary image and store in some Mat variable img as discussed earlier. Now I have got another image (.gif image) which I cannot load as shown below:
Now I want to compare my img image (binary) with the given .gif image (above) which I cannot load.
Use ImageMagic for converting your .gif to .PNG in batch mode. You could also convert it on the fly using system("convert img.gif img.png") call.
I'm not sure, if pixel comparison will give you good result. An offset shift of the same image will result in bad match.
EDIT As an idea. Maybe calculating centers of gravity and shifting/rotating both images to have the same origin may help here.
Consider using moments, freeman chain or other mode robust shape comparison methods.
first off you will want to use the images in the same format as each other #Adi mentioned jpg is lossy in the comments which is correct so shouldn't be used until possibly after any work is done. MATLAB - image conversion
you will also want the images to be of the same size. you can compare them using the size function and then pad them to add pixels to make the dimensions the same. the padding can always be removed later, just watch how the padding is added so as not to affect your operations.
you will also need to look into rotations, consider putting the image into the frequency domain and rotate the image to align the spectrum's.
below is a simple pixel comparison code, pixel comparison is not particularly accurate for comparing. even the slightest miss alignment will cause false negatives or false positives.
%read image
test_image1 = imread('C:\Users\Public\Pictures\Sample Pictures\Desert.jpg');
test_image2 = imread('C:\Users\Public\Pictures\Sample Pictures\Hydrangeas.jpg');
%convert to gray scale
gray_img1 = rgb2gray(test_image1);
gray_img2 = rgb2gray(test_image2);
% threshold image to put all values greater than 125 to 255 and all values
% below 125 to 0
binary_image1 = gray_img1 > 125;
binary_image2 = gray_img2 > 125;
%binary image to size to allow pixel by pixel checking
[row, col] = size(binary_image1);
% initialize the counters for similar and different pixelse to zero
similar = 0;
different = 0;
%two loops to scan through all rows and columns of the image.
for kk = 1 : row
for yy = 1 : col
%using if statement with isequal function to compare corresponding
%pixel values and count them depending ont he logical output of
%isequal
if isequal(binary_image1(kk,yy), binary_image2(kk,yy))
similar = similar + 1;
else
different = different + 1;
end
end
end
% calculate the percentage difference between the images and print it
total_pixels = row*col;
difference_percentage = (different / total_pixels) * 100;
fprintf('%f%% difference between the compared images \n%d pixels being different to %d total pixels\n', difference_percentage, different, total_pixels )
% simple supbtraction of the two images
diff_image = binary_image1 - binary_image2;
%generate figure to show the original gray and corresponding binary images
%as well as the subtraction
figure
subplot(2,3,1)
imshow(gray_img1);
title('gray img1');
subplot(2,3,2)
imshow(gray_img2);
title('gray img2');
subplot(2,3,4)
imshow(binary_image1);
title('binary image1');
subplot(2,3,5)
imshow(binary_image2);
title('binary image2');
subplot(2,3,[3,6])
imshow(diff_image);
title('diff image');

How do I denoise a simple grayscale image

Here is the original image with better vision: we can see a lot of noise around the main skeleton, the circle thing, which I want to remove them, and do not affect the main skeleton. I'm not sure if it called noise
I'm doing it to deblurring a image, and this image is the motion blur kernel which identify the camera motion when the camera capture a image.
ps: this image is the kernel for one case, and what I need is a general method in here. thank you for your help
there is a paper in CVPR2014 named "Separable Kernel for Image Deblurring" which talk about this, I want to extract main skeleton of the image to make the kernel more robust, sorry for the explaination here as my English is not good
and here is the ture grayscale image:
I want it to be like this:
How can I do it using Matlab?
here are some other kernel images:
As #rayryeng well explained, median filtering is the best option to clean noise in the image, which I realized when I had studied about image restoration. However, in your case, what you need to do seems to me not cleaning noise in the image. You want to more likely eliminate the sparks in the image.
Simply I applied single thresholding to your noisy image to eliminate sparks.
Try this:
desIm = imread('http://i.stack.imgur.com/jyYUx.png'); % // Your expected (desired) image
nIm = imread('http://i.stack.imgur.com/pXO0p.png'); % // Your original image
nImgray = rgb2gray(nIm);
T = graythresh(nImgray)*255; % // Thereshold value
S = size(nImgray);
R = zeros(S) + 5; % // Your expected image bluish so I try to close it
G = zeros(S) + 3; % // Your expected image bluish so I try to close it
B = zeros(S) + 20; % // Your expected image bluish so I try to close it
logInd = nImgray > T; % // Logical index of pixel exclude spark component
R(logInd) = nImgray(logInd); % // Get original pixels without sparks
G(logInd) = nImgray(logInd); % // Get original pixels without sparks
B(logInd) = nImgray(logInd); % // Get original pixels without sparks
rgbImage = cat(3, R, G, B); % // Concatenating Red Green Blue channels
figure,
subplot(1, 3, 1)
imshow(nIm); title('Original Image');
subplot(1, 3, 2)
imshow(desIm); title('Desired Image');
subplot(1, 3, 3)
imshow(uint8(rgbImage)); title('Restoration Result');
What I got is:
The only thing I can see that is different between the two images is that there is some quantization noise / error around the perimeter of the object. This resembles salt and pepper noise and the best way to remove that noise is to use median filtering. The median filter basically analyzes local overlapping pixel neighbourhoods in your image, sorts the intensities and chooses the median value as the output for each pixel neighbourhood. Salt and pepper noise corrupts image pixels by randomly selecting pixels and setting their intensities to either black (pepper) or white (salt). By employing the median filter, sorting the intensities puts these noisy pixels at the lower and higher ends and by choosing the median, you would get the best intensity that could have possibly been there.
To do median filtering in MATLAB, use the medfilt2 function. This is assuming you have the Image Processing Toolbox installed. If you don't, then what I am proposing won't work. Assuming that you do have it, you would call it in the following way:
out = medfilt2(im, [M N]);
im would be the image loaded in imread and M and N are the rows and columns of the size of the pixel neighbourhood you want to analyze. By choosing a 7 x 7 pixel neighbourhood (i.e. M = N = 7), and reading your image directly from StackOverflow, this is the result I get:
Compare this image with your original one:
If you also look at your desired output, this more or less mimics what you want.
Also, the code I used was the following... only three lines!
im = rgb2gray(imread('http://i.stack.imgur.com/pXO0p.png'));
out = medfilt2(im, [7 7]);
imshow(out);
The first line I had to convert your image into grayscale because the original image was in fact RGB. I had to use rgb2gray to do that. The second line performs median filtering on your image with a 7 x 7 neighbourhood and the final line shows the image in a separate window with imshow.
Want to implement median filtering yourself?
If you want to get an idea of how to actually write a median filtering algorithm yourself, check out my recent post here. A question poser asked to implement the filtering mechanism without using medfilt2, and I provided an answer.
Matlab Median Filter Code
Hope this helps.
Good luck!

Detection of homogeneous area in term of connectivity in image

I am looking for some measurements to do to distinct between these two binary images (texte and noise).
Hough transform of the frequency domain don't tell me much (either in skeleton or in the original shape), as can be seen below !
in the spatial domain, I have try to measure, if a given pixel participate to line or curve, or participate to a random shape, and then measures the percentage of all pixels participating and not participating to normal shape (lines and curves) to distinguish between these images, but I didn't succeed, in implementation.
what do you think ?
I use matlab for test.
Thanks in advance
Looking at the skeleton images, one could notice how the noise image has lots of branches in it, as compared to the text image and this looks like one of the features that could be exploited. The experiment as code shown below soughts to verify the same, using the OP's images -
Experiment Code
%%// Experiment to research what features what might help us
%%// differentiate betwen noise and text images
%%// Read in the given images
img1 = imread('noise.png');
img2 = imread('text.png');
%%// Since the given images had the features as black and rest as white,
%%// we must invert them
img1 = ~im2bw(img1);
img2 = ~im2bw(img2);
%%// Remove the smaller blobs from both of the images which basically
%%// denote the actual noise in them
img1 = rmnoise(img1,60);
img2 = rmnoise(img2,60);
%// Get the skeleton images
img1 = bwmorph(img1,'skel',Inf);
img2 = bwmorph(img2,'skel',Inf);
%%// Find blobs branhpoints for each blob in both images
[L1, num1] = bwlabel(img1);
[L2, num2] = bwlabel(img2);
for k = 1:num1
img1_bpts_count(k) = nnz(bwmorph(L1==k,'branchpoints'));
end
for k = 1:num2
img2_bpts_count(k) = nnz(bwmorph(L2==k,'branchpoints'));
end
%%// Get the standard deviation of branch points count
img1_branchpts_std = std(img1_bpts_count)
img2_branchpts_std = std(img2_bpts_count)
Note: Above code uses a function - rmnoise shown below that is built based on the problem discussed at this link :
function NewImg = rmnoise(Img,threshold)
[L,num] = bwlabel( Img );
counts = sum(bsxfun(#eq,L(:),1:num));
B1 = bsxfun(#eq,L,permute(find(counts>threshold),[1 3 2]));
NewImg = sum(B1,3)>0;
return;
Output
img1_branchpts_std =
73.6230
img2_branchpts_std =
12.8417
One can see the big difference between the standard deviations of the two input images, suggesting this feature could be used.
Runs on some other samples
To make our theory a bit more concrete, let's use a pure text image and gradually add noise and see if the standard deviation of branch-points, naming it as check_value suggest anything on them.
(I) Pure text image
check_value = 1.7461
(II) Some added noise image
check_value = 30.1453
(III) Some more added noise image
check_value = 54.6446
Conclusion: As can be seen, this parameter provides quite a good indicator to decide on the nature of images.
Finalized Code
A script could be written to test for whether another input image would be a text or noise one, like this -
%%// Parameters
%%// 1. Decide this based on the typical image size and count of pixels
%%// in the biggest noise blob
rmnoise_threshold = 60;
%%// 2. Decide this based on the typical image size and how convoluted the
%%// noisy images are
branchpts_count_threshold = 50;
%%// Actual processing
%%// We are assuming input images as binary images with features as true
%%// and false in rest of the region
img1 = im2bw(imread(FILE));
img1 = rmnoise(img1,rmnoise_threshold);
img1 = bwmorph(img1,'skel',Inf);
[L1, num1] = bwlabel(img1);
for k = 1:num1
img1_bpts_count(k) = nnz(bwmorph(L1==k,'branchpoints'));
end
if std(img1_bpts_count) > branchpts_count_threshold
disp('This is a noise image');
else
disp('This is a text image');
end
And now what you suggest if we try to use the original shape instead of the skeleton, (to avoid the loss of information).
I try to measure for a given pixel, the elongation of the strokes (instead of straight branches) that past throughout that pixel, by counting the number of transitions from white to black in a clockwise.
I am thinking to use a circle with a radius, and for the origin the pixel in consideration, and store the pixels locating at the edge of the circle in an ordered list (clockwise) and then compute the number of transitions (black to white) from this list.
by increasing the radius of the circle we could trace the shape of elongated stokes and know his orientation.
this is a schema illustrating this.
the pixels that have a number of transitions equal to 0 or bigger than 2 (red ones) have to be classified as noise, and those that have 2 or 1 transition classified as normal.
What do you think of this approach !