Image single background color - Matlab - matlab

In the code below I rotated an image. How can I get a single background color (white or black)?
code:
close all;
clear;
clc;
url='http://www.clker.com/cliparts/T/i/o/c/X/Q/airplane-md.png';
RI = imread(url);
I = rgb2gray(RI);
BI = imbinarize(I);
LI = bwlabel(BI);
mea = regionprops(LI, 'All');
RI = imrotate(RI, -mea(1).Orientation,'loose');
imshow(RI);

Given that the image is a simple logo (as opposed to a photo for instance) you can likely use logical indexing to change all of the black pixels added by imrotate to white pixels.
I don't have the image processing toolbox so I couldn't run your code, but the sample below should illustrate:
%Load RBG image to test on
RI = imread('peppers.png');
%Create black region to remove
RI(100:150,100:150,:) = 0;
figure()
imshow(RI)
title('Original Image')
%Replace all black pixels with white
inds = sum(RI,3)==0;
RI_new = RI;
RI_new(repmat(inds,1,1,3))=255;
figure()
imshow(RI_new)
title('New Image')
In comparison to the answer from #SardarUsama, this has the weakness of assuming there are no black pixels in your original image but the advantage of using built-in Matlab functions only.
Edit: Updated to show example on RGB image rather than grayscale

Your original image has white background. When you rotate it, you get black pixels in the background to fill up the image matrix. This may be due to that the preallocation of the rotated image matrix is done with zeros which then translates to black (implemented probably in imrotatemex and in the lines 116 and 118 of imrotate). You can use these alternate implementations of imrotate but preallocate the matrix with ones (for double data) or 255 (for uint8 data).
For example, in line 31 of Rody's implementation, i.e.:
imagerot = zeros([max(dest) p],class(image));
Change this line to:
imagerot = 255*ones([max(dest) p],'uint8'); %Your image is uint8 in this case
Result:

Related

Find biggest contour for shadow detection

I have this problem in image processing and I couldn't find an algorithm to perform well under this condition.It's so simple to understand but I don't know how to implement it in ‍‍OpenCV or in Matlab, so any algorithm or function in one of them (MATLAB or opencv) is helpful.
1 . lets suppose that an image and background of scene is like the below
2 . We apply an edge detector to image and my current image will be like the below picture.
now my Problem is that how we can find the biggest contour or area like the below in edge image?
If you want original picture the original picture is
and in matlab you can get edge image by below codes.
clc
clear
img = imread('1.png'); % read Image
gray = rgb2gray(img); % Convert RGB to gray-scale
edgeImage = edge(gray,'canny',0.09); % apply canny to gray-scale image
imshow(edgeImage) % Display result in figure(MATLAB)
In OpenCV you can use below code
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
Mat img = imread("1.png");
Mat gray;
cvtColor(img, //BGR form image
gray, //Mat for gray(destination)
CV_BGR2GRAY); //type of transform(in here BGR->GRay)
Mat edgeImage;
Canny(gray, //Input Array
edgeImage, //Output Array
40, // Lower threshold
120); //Upper threshold
namedWindow("Edge-Image"); //create a window for display image
imshow("Edge-Image",edgeImage); //Display edgeImage in window that in before line create
waitKey(0); //stick display window and wait for any key
return 0;
}
Here is a solution in Matlab using imdilate to close the contours and regionprops to get the closed objects area:
% Your code to start
img = imread('Image.png'); % read Image
gray = rgb2gray(img); % Convert RGB to gray-scale
edgeImage = edge(gray,'canny',0.09); % apply canny to gray-scale image
% First dilate to close contours
BW = imdilate(edgeImage, strel('disk',4,8));
% Then find the regions
R = regionprops(~BW, {'Area', 'PixelIdxList'});
% Find the second biggest region (the biggest is the background)
[~, I] = sort([R(:).Area], 'descend');
Mask = zeros(size(img));
Mask(R(I(2)).PixelIdxList) = 1;
% Display
clf
imshow(Mask)
An the result is:
Best,
First close the contour with morphological closing since you can't find it now as it is not really a distinct contour, but a part of the larger one.
After closing, just use the findContours() function and use its output to get the area of each contour and eventually find the maximum one by using the contourArea() function.

Watershed Algorithm setting removing all connected components

I'm using the watershed algorithm to try and segment touching nuclei. A typical image may look like:
or this:
I'm trying to apply the watershed algorithm with this code:
show(RGB_img)
%Convert to grayscale image
I = rgb2gray(RGB_img);
%Take structuring element of a disk of size 10, for the morphological transformations
%Attempt to subtract the background from the image: top hat is the
%subtraction of the open image from the original
%Morphological transformation to subtract background noise from the image
%Tophat is the subtraction of an opened image from the original. Remove all
%images smaller than the structuring element of 10
I1 = imtophat(I, strel('disk', 10));
%Increases contrast
I2 = imadjust(I1);
%show(I2,'contrast')
%Assume we have background and foreground and assess thresh as such
level = graythresh(I2);
%Convert to binary image based on graythreshold
BW = im2bw(I2,level);
show(BW,'C');
BW = bwareaopen(BW,8);
show(BW,'C2');
BW = bwdist(BW) <= 1;
show(BW,'joined');
%Complement because we want image to be black and background white
C = ~BW;
%Use distance tranform to find nearest nonzero values from every pixel
D = -bwdist(C);
%Assign Minus infinity values to the values of C inside of the D image
% Modify the image so that the background pixels and the extended maxima
% pixels are forced to be the only local minima in the image (So you could
% hypothetically fill in water on the image
D(C) = -Inf;
%Gets 0 for all watershed lines and integers for each object (basins)
L = watershed(D);
show(L,'L');
%Takes the labels and converts to an RGB (Using hot colormap)
fin = label2rgb(L,'hot','w');
% show(fin,'fin');
im = I;
%Superimpose ridgelines,L has all of them as 0 -> so mark these as 0(black)
im(L==0)=0;
clean_img = L;
show(clean_img)
For whatever reason after C = ~BW; the whole image goes dark. This very same code block has worked on a handful of other images, all of which were more "solid" or not as grainy as these. However, I thought I compensated for this with BW = bwdist(BW) <= 1;. I've experimented a ton and I don't really know what's happening. Any help would be great!
Ps. this is the image after BW = bwareaopen(BW,8);
Before the top-hat, you should perform a closing and an opening in order to reduce the noise.
If you perform an area opening on a noisy image, you may end up with the result on your black and white image.
So it would be:
Closing and opening
Top-Hat
Area opening if still necessary
Thresholding
Erosion and dilation to find the inner and outer markers respectively
Watershed (never use a watershed without markers).

Negative values in Watershed algorithm leading to black image

I'm using the watershed algorithm to try and segment touching nuclei. A typical image may look like:
or this:
I'm trying to apply the watershed algorithm with this code:
show(RGB_img)
%Convert to grayscale image
I = rgb2gray(RGB_img);
%Take structuring element of a disk of size 10, for the morphological transformations
%Attempt to subtract the background from the image: top hat is the
%subtraction of the open image from the original
%Morphological transformation to subtract background noise from the image
%Tophat is the subtraction of an opened image from the original. Remove all
%images smaller than the structuring element of 10
I1 = imtophat(I, strel('disk', 10));
%Increases contrast
I2 = imadjust(I1);
%show(I2,'contrast')
%Assume we have background and foreground and assess thresh as such
level = graythresh(I2);
%Convert to binary image based on graythreshold
BW = im2bw(I2,level);
show(BW,'C');
BW = bwareaopen(BW,8);
show(BW,'C2');
BW = bwdist(BW) <= 1;
show(BW,'joined');
%Complement because we want image to be black and background white
C = ~BW;
%Use distance tranform to find nearest nonzero values from every pixel
D = -bwdist(C);
%Assign Minus infinity values to the values of C inside of the D image
% Modify the image so that the background pixels and the extended maxima
% pixels are forced to be the only local minima in the image (So you could
% hypothetically fill in water on the image
D(C) = -Inf;
%Gets 0 for all watershed lines and integers for each object (basins)
L = watershed(D);
show(L,'L');
%Takes the labels and converts to an RGB (Using hot colormap)
fin = label2rgb(L,'hot','w');
% show(fin,'fin');
im = I;
%Superimpose ridgelines,L has all of them as 0 -> so mark these as 0(black)
im(L==0)=0;
clean_img = L;
show(clean_img)
After C = ~BW; the whole image goes dark. I believe this is because the image pixels are all -inf or some smaller negative number. This is there a way around this and if so what could I change in my code to get this algorithm working? I've experimented a ton and I don't really know what's happening. Any help would be great!
The problem is with your show command. As you said in the comments this uses imshow under the hood. If you try imshow directly you'll see you also get a black image. However, if you call it with appropriate limits:
imshow(clean_img,[min(clean_img(:)), max(clean_img(:))])
you'll see everything you expect to see.
In general I usually prefer imagesc for that reason. imshow makes arbitrary judgements as to what range to represent, and I usually can't be bothered to keep up with it. I think in your case, your end image is uint16 so imshow chooses to represent the range [1, 65025]. Since all your pixel values are below 400, they look black to the naked eye for that range.

what is the right way to compute the measures for images with different color properties

I need a little help guys in Matlab in Matrix Dimensions,
I Have two images imported by imread function:
im1 = imread('1.jpg');
im2 = imread('2.jpg');
im1 is the reference image, while im2 is the Noisy image.
In the workspace window, Matlab shows the im2 Dimensions like this: 768x1024x3
while im2 displayed as: 768x1024
They are both RGB, there's no greyscale images,
In fact the second image is the a compressed image (performed compression algorithm on it ) while the first image is natural JPEG Image, untouched
and for calculating MSE/PNSR for both images, the matrix dimensions must be the same.
I Will need to transform im1 dimensions to be 3d like the first image (768x1024)
I tried this functions (squeeze, reshape) and with no success
You were on the right track with repmat. Here's the correct syntax:
im2 = repmat(im2, [1 1 3]);
This says you want 1 replicate along the first dimension, 1 replicate along the second dimension, and 3 replicates along the third dimension.
Are you sure that both are RGB images because im2 has only one channel and it looks grayscale but it can also be a colormap image in that case try
[im2, map] = imread('im2.jpg');
and see if anything is appearing in map variable. If the image is indeed colormap image, the map variable should be of size 256 X 3.
What donda has suggested is repeating the grayscale channel 3 times to make it of size 768x1024x3. Another possibility is that noisy image was created by converting RGB image to grayscale or by taking green channel of RGB image. Verify the source of the image in that case.
About PSNR computation I have a feeling that there is some problem with your code. I have given my code below use this and see if it works. Get back to me if you face any problem.
function [Psnr_DB] = psnr(I,I_out)
I = double(I);
I_out = double(I_out);
total_error = 0;
for iterz = 1:size(I,3)
for iterx = 1:size(I,1)
for itery = 1:size(I,2)
total_error = total_error + (I(iterx,itery,iterz)-I_out(iterx,itery,iterz))^2;
end
end
end
MSE = total_error/numel(I);
Psnr = (255^2)/MSE;
Psnr_DB = 10*log10(Psnr) %#ok<NOPRT>

remove the holes in an image by average values of surrounding pixels

can any one please help me in filling these black holes by values taken from neighboring non-zero pixels.
thanks
One nice way to do this is to is to solve the linear heat equation. What you do is fix the "temperature" (intensity) of the pixels in the good area and let the heat flow into the bad pixels. A passable, but somewhat slow, was to do this is repeatedly average the image then set the good pixels back to their original value with newImage(~badPixels) = myData(~badPixels);.
I do the following steps:
Find the bad pixels where the image is zero, then dilate to be sure we get everything
Apply a big blur to get us started faster
Average the image, then set the good pixels back to their original
Repeat step 3
Display
You could repeat averaging until the image stops changing, and you could use a smaller averaging kernel for higher precision---but this gives good results:
The code is as follows:
numIterations = 30;
avgPrecisionSize = 16; % smaller is better, but takes longer
% Read in the image grayscale:
originalImage = double(rgb2gray(imread('c:\temp\testimage.jpg')));
% get the bad pixels where = 0 and dilate to make sure they get everything:
badPixels = (originalImage == 0);
badPixels = imdilate(badPixels, ones(12));
%# Create a big gaussian and an averaging kernel to use:
G = fspecial('gaussian',[1 1]*100,50);
H = fspecial('average', [1,1]*avgPrecisionSize);
%# User a big filter to get started:
newImage = imfilter(originalImage,G,'same');
newImage(~badPixels) = originalImage(~badPixels);
% Now average to
for count = 1:numIterations
newImage = imfilter(newImage, H, 'same');
newImage(~badPixels) = originalImage(~badPixels);
end
%% Plot the results
figure(123);
clf;
% Display the mask:
subplot(1,2,1);
imagesc(badPixels);
axis image
title('Region Of the Bad Pixels');
% Display the result:
subplot(1,2,2);
imagesc(newImage);
axis image
set(gca,'clim', [0 255])
title('Infilled Image');
colormap gray
But you can get a similar solution using roifill from the image processing toolbox like so:
newImage2 = roifill(originalImage, badPixels);
figure(44);
clf;
imagesc(newImage2);
colormap gray
notice I'm using the same badPixels defined from before.
There is a file on Matlab file exchange, - inpaint_nans that does exactly what you want. The author explains why and in which cases it is better than Delaunay triangulation.
To fill one black area, do the following:
1) Identify a sub-region containing the black area, the smaller the better. The best case is just the boundary points of the black hole.
2) Create a Delaunay triangulation of the non-black points in inside the sub-region by:
tri = DelaunayTri(x,y); %# x, y (column vectors) are coordinates of the non-black points.
3) Determine the black points in which Delaunay triangle by:
[t, bc] = pointLocation(tri, [x_b, y_b]); %# x_b, y_b (column vectors) are coordinates of the black points
tri = tri(t,:);
4) Interpolate:
v_b = sum(v(tri).*bc,2); %# v contains the pixel values at the non-black points, and v_b are the interpolated values at the black points.