Best way to pad image based on the edge pixels (row-wise) - image

I want to pad an object based on edge pixel to replace the zeros.
I am not sure if padarray is applicable to this, I am showing a sample code below to replicate my need. I am able to do it but I think this is not an efficient way as I am scanning each row at a time to find and pad the zeros.
%% Example code to recreate my need
image = imread('moon.tif');
[~, ncols] = size(image);
image(image <50) = 0;
image = fliplr(image(:,1:round(ncols/2)));
% figure, imshow(image,[])
BW = bwareafilt(logical(image),1);
% create bounding box
boxProps=regionprops(BW,'BoundingBox');
cords_BoundingBox = boxProps(1).BoundingBox;
% Extract sub_Image
sub_Image = imcrop(image, cords_BoundingBox);
% figure, imshow(sub_Image,[])
%% This is the part I want to use better or existing function for padding
duplicate_sub_Image = sub_Image;
[nrows, ~] = size(duplicate_sub_Image);
for nrow = 1:nrows
% current_row_inverted = fliplr(sub_Image(nrow,:));
[~,col,pad_value] = find(duplicate_sub_Image(nrow,:),1,'last');
duplicate_sub_Image(nrow,col+1:end) = pad_value;
end
figure,
subplot(131),imshow(image,[]), title('original image');
subplot(132),imshow(sub_Image,[]), title('bounding box image');
subplot(133),imshow(duplicate_sub_Image,[]), title('row padded image');
Any suggestions to improve this code or use of existing functions to address this issue?
Thanks

Here is a way without using loops:
[~,imin] = min(sub_Image, [], 2);
col = max(1, imin-1);
ind = sub2ind(size(sub_Image), (1:numel(col)).', col);
duplicate_sub_Image = sub_Image(ind) .* ~sub_Image + sub_Image;

Related

how to make smooth and remove the white edge? Besides, why the black lines arise in my answer? How to solve it?

Based on Shai and Biguri's codes and comments, I have finished a color picture like this:
A problem arises, how to remove the white edge and make it smooth? One solution may be to build 3x3 matrix or bigger and average. But the calculations should be large for every white-edge points. Or there may be some useful functions in Matlab to deal well with this problems?
If you have a license for the image processing toolbox, you can try using for example medfilt2 to apply a median filter on the image. A 11 by 11 median filter should do the trick. It is not very difficult to reimplement the filter yourself if you don't have the toolbox.
This is just one of the possibilities, you can use many different filters that will have different impacts on sharpness ang edge removal.
Edit:
Here is a quick median filter implementation (it may contain errors and could be optimized):
function ret = imageMedianFilter(im, np)
if(size(np,2) == 1)
npx = np;
npy = np;
else
npx = np(1);
npy = np(2);
end
ret = zeros(size(im,1),size(im,2));
for xpos = 1:size(im,1)
for ypos = 1:size(im,2)
curval = double(0);
if(xpos + npx - 1) > size(im,1)
npixels_x = size(im,1) - xpos + 1;
else
npixels_x = npx;
end
if(ypos + npy - 1) > size(im,2)
npixels_y = size(im,2) - ypos + 1;
else
npixels_y = npy;
end
a = im(xpos:xpos+npixels_x-1 , ypos:ypos+npixels_y-1);
a = reshape(a,1,size(a,1)*size(a,2));
curval = median(a);
ret(xpos , ypos) = curval;
end
end
ret = uint8(ret);
end
You can use it on R,G and B components as shown by Rotem below:
RGB = cat(3, imageMedianFilter(RGB(:,:,1), [11,11]), imageMedianFilter(RGB(:,:,2), [11,11]), imageMedianFilter(RGB(:,:,3), [11,11]));
(assuming your image is named RGB).
Here is my solution. I take n*n patch to average the near RGB. But there is a problem arising. Why the right down side of processed picture showing black lines?
clc;clf;close all;clear all;
img = imread('sample2color_t1.bmp'); %// read image
bw = img(:,:,1) > 128; %// convert to binary mask
[lb,lab] = bwlabel(bw,4); %// extract distinct regions
[a,b,c]=size(img);
R=ones(a,b);
G=ones(a,b);
B=ones(a,b);
%I have omitted other colors process codes. Below it is the white edges code.
r=[];c=[];
[r,c] = find(lb ==0);
for i=1:length(r)
R(r(i),c(i))=1;
G(r(i),c(i))=1;
B(r(i),c(i))=1;
end
scale=5;%步长1,8连通
for i=1:length(r)
sumR=0;sumG=0;sumB=0;
for j=0:2*scale
for k=0:2*scale
sumR=sumR+R(r(i)-scale+j,c(i)-scale+k);
sumG=sumG+G(r(i)-scale+j,c(i)-scale+k);
sumB=sumB+B(r(i)-scale+j,c(i)-scale+k);
end
end
R(r(i),c(i))=sumR/(2*scale+1)^2;
G(r(i),c(i))=sumG/(2*scale+1)^2;
B(r(i),c(i))=sumB/(2*scale+1)^2;
end
imPaint=cat(3,R,G,B);
figure;
imshow(imPaint);

Plot over an image background in MATLAB

I'd like to plot a graph over an image. I followed this tutorial to Plot over an image background in MATLAB and it works fine:
% replace with an image of your choice
img = imread('myimage.png');
% set the range of the axes
% The image will be stretched to this.
min_x = 0;
max_x = 8;
min_y = 0;
max_y = 6;
% make data to plot - just a line.
x = min_x:max_x;
y = (6/8)*x;
imagesc([min_x max_x], [min_y max_y], img);
hold on;
plot(x,y,'b-*','linewidth',1.5);
But when I apply the procedure to my study case, it doesn't work. I'd like to do something like:
I = imread('img_png.png'); % here I load the image
DEM = GRIDobj('srtm_bigtujunga30m_utm11.tif');
FD = FLOWobj(DEM,'preprocess','c');
S = STREAMobj(FD,flowacc(FD)>1000);
% with the last 3 lines I calculated the stream network on a geographic area using the TopoToolBox
imagesc(I);
hold on
plot(S)
The aim is to plot the stream network over the satellite image of the same area.
The only difference between the two examples that doesn't let the code working is in the plot line, in the first case "plot(x,y)" works, in the other one "plot(S)" doesn't.
Thanks guys.
This is the satellite image, imagesc(I)
It is possible that the plot method of the STREAMobj performs it's own custom plotting including creating new figures, axes, toggling hold states, etc. Because you can't easily control what their plot routine does, it's likely easier to flip the order of your plotting so that you plot your stuff after the toolbox plots the STREAMobj. This way you have completely control over how your image is added.
% Plot the STREAMobj
hlines = plot(S);
% Make sure we plot on the same axes
hax = ancestor(hlines, 'axes');
% Make sure that we can add more plot objects
hold(hax, 'on')
% Plot your image data on the same axes
imagesc(I, 'Parent', hax)
Maybe I am preaching to the choir or overlooking something here but the example you used actually mapped the image to the data range of the plot, hence the lines:
% set the range of the axes
% The image will be stretched to this.
min_x = 0;
max_x = 8;
min_y = 0;
max_y = 6;
imagesc([min_x max_x], [min_y max_y], img);
where you directly plot your image
imagesc(I);
If now your data coordinates and your image coordinates are vastly different you either see one or the other.
Thanks guys, I solved in this way:
I = imread('orto.png'); % satellite image loading
DEM = GRIDobj('demF1.tif');
FD = FLOWobj(DEM,'preprocess','c');
S = STREAMobj(FD,flowacc(FD)>1000); % Stream network extraction
x = S.x; % [node attribute] x-coordinate vector
y = S.y; % [node attribute] y-coordinate vector
min_x = min(x);
max_x = max(x);
min_y = min(y);
max_y = max(y);
imagesc([min_x max_x], [min_y max_y], I);
hold on
plot(S);
Here's the resulting image: stream network over the satellite image
Actually the stream network doesn't match the satellite image just because I'm temporarily using different images and DEM.

Skipping some axis labels in a plot with imagesc

I have created a big heat map using matlab's imagesc command. It plots the error output for each combination of the values in x and y axes. As can be seen in the figure there are too many axes labels. This might become even denser as I plan to increase the number of points in both x and y axes - which means I will get more outputs on a finer grid.
I want to be flexible with the labels, and skip some of them. I want to do this for both X and Y. I also want to be flexible with the "ticks" and draw either all of them or maybe skip some of them. Keep in mind that both the X and Y values are not increasing in order, at first the increment is 0.01 for 9 points, then 0.1, then 1 or 3 or whatever. I will change these increments too.
I tried to show what I want the graph look like in the second image. I want roughly the labels shown in red boxes only. As I said these are not set values, and I will make the increments smaller which will lead to denser plot.
Thank you for your help.
OS: Windows 7, 8 (64 bit)
Matlab version: Matlab 2014 a
You can manipulate the ticks and labels like this:
ticksarray=[1 33 41 100 ...] % edit these to whatever you want
tickslabels={'1', '33', '41', '100'; ...} % match the size of both arrays
set(gca,'XTick',ticksarray)
set(gca,'XTickLabel',tickslabels)
The same thing applies to the y-axis.
Small working example:
x=1:100;
y=2*x.^2-3*x+2;
plot(x,y)
ticksarray=[1 33 41 100];
tickslabels={'1', '33', '41', '100'};
set(gca,'XTick',ticksarray)
set(gca,'XTickLabel',tickslabels)
Example:
figure(1)
load clown
subplot(211)
imagesc(X);
subplot(212)
imagesc(X);
h = gca;
Now you can either set a maximum number of labels per axis:
%// define maximum number of labels
maxLabel = 3;
h.XTick = linspace(h.xlim(1),h.xlim(2),maxLabel);
h.YTick = linspace(h.ylim(1),h.ylim(2),maxLabel);
or define how many labels should be skipped:
%// define number of labels to skip
skipLabel = 2;
h.XTick = h.XTick(1:skipLabel:end);
h.YTick = h.YTick(1:skipLabel:end)
You can also get a different number of ticks and labels, more complicated though:
maxLabel = 3;
maxTicks = 6;
h.XTick = linspace(h.xlim(1),h.xlim(2),maxTicks);
h.YTick = linspace(h.ylim(1),h.ylim(2),maxTicks);
h.XTickLabel( setdiff( 1:maxTicks, 1:maxTicks/maxLabel:maxTicks ) ) = repmat({''},1,maxTicks-maxLabel);
h.YTickLabel( setdiff( 1:maxTicks, 1:maxTicks/maxLabel:maxTicks ) ) = repmat({''},1,maxTicks-maxLabel);
If you use a prior version of Matlab 2014b, then you will need the set command to set all properties:
%// define maximum number of labels
maxLabel = 3;
Xlim = get(h,'Xlim');
Ylim = get(h,'Ylim');
set(h,'XTick', linspace(Xlim(1),Xlim(2),maxLabel));
set(h,'YTick', linspace(Ylim(1),Ylim(2),maxLabel));
%// or define number of labels to skip
skipLabel = 2;
XTick = get(h,'XTick');
YTick = get(h,'YTick');
set(h,'XTick', XTick(1:skipLabel:end));
set(h,'YTick', YTick(1:skipLabel:end));
%// or combined
maxLabel = 3;
maxTicks = 6;
Xlim = get(h,'Xlim');
Ylim = get(h,'Ylim');
set(h,'XTick', linspace(Xlim(1),Xlim(2),maxTicks));
set(h,'YTick', linspace(Ylim(1),Ylim(2),maxTicks));
XTickLabel = cellstr(get(h,'XTickLabel'));
YTickLabel = cellstr(get(h,'YTickLabel'));
XTickLabel( setdiff( 1:maxTicks, 1:maxTicks/maxLabel:maxTicks ),: ) = repmat({''},1,maxTicks-maxLabel);
YTickLabel( setdiff( 1:maxTicks, 1:maxTicks/maxLabel:maxTicks ),: ) = repmat({''},1,maxTicks-maxLabel);
set(h,'XTickLabel',XTickLabel);
set(h,'YTickLabel',YTickLabel);
After applying the second method proposed by #thewaywewalk I got the second figure below. Apparently the labels need to be structured as well, because they only take the first so many labels.
Then I tried to manipulate the labels as shown below, and got the third image.
skipLabel = 2;
XTick = get(h,'XTick');
YTick = get(h,'YTick');
set(h,'XTick', XTick(1:skipLabel:end));
set(h,'YTick', YTick(1:skipLabel:end));
XTickLabel = get(h,'XTickLabel');
labelsX = cell( length(1: skipLabel:length(XTick)) , 1);
j = 1;
for i = 1: skipLabel:length(XTick)
labelsX{j} = XTickLabel(i, :);
j = j + 1;
end
set(h,'XTickLabel', labelsX);
YTickLabel = get(h,'YTickLabel');
labelsY = cell( length(1: skipLabel:length(YTick)) , 1);
j = 1;
for i = 1: skipLabel:length(YTick)
labelsY{j} = YTickLabel(i, :);
j = j + 1;
end
set(h,'YTickLabel', labelsY);
The Y axis labels seem to be in place as before (right next to tick), however the X axis labels seem to be shifted to the left a little. How can I correct this?
Another note: How can I change the scientific values into normal numbers? Also, probably there is a better approach at manipulating the labels.

How to reconstruct an image using rgb values of all pixels in Matlab

I am trying to read an image using imread then, save the RGB values of all of the pixels in an array. And finally, be able to recreate this image using only the RGB values.
This is the for loop that saves all of the RGB values of each pixel.
A=imread('image.jpg');
N=2500; %the image dimensions are 50x50
i=1;
rgbValues = zeros(N, 3);
for x = 1:50
for y = 1:50
rgbValues(i,:) = A(x,y,:);
i=i+1;
end
end
Now, how am I able to recreate this image if I have all of the rgb values saved.
A direct way to do this is:
ny = 50;
nx = 50;
recreatedImage = zeros(ny,nx,3, 'uint8');
for ind = 1:3
recreatedImage(:,:, ind) = ( reshape(rgbValues(:, ind), nx, ny))';
end
As Natan indicated, reshape will work also but you have to do this:
recreatedImage=reshape(rgbValues,[ny,nx,3]);
Which is, unfortunately, transposed so you will need to work it to get it rotated back up.
You might consider swapping your x and y values in your for loop so you iterate over all y and then all x values---because this is how MATLAB stores the data and you can change the above code to:
for ind = 1:3
recreatedImage(:,:, ind) = ( reshape(rgbValues(:, ind), ny, nx));
end
(edit) and then the direct reshape works as well:
rgbValuesBacktoShape=reshape(rgbValues,[50,50,3]);

How to find more than one matching pattern using Normalized Correalation

I'm using normxcorr2 to find the area that exactly match with my pattern and i also want to find the other area(in the red rectangle) that is look like the pattern. I think it will be works if i can find the next maximum and so on and that value must not in the first maximum area or the first one that it has been detected but i can't do it. Or if you have any idea that using normxcorr2 to find the others area please advise me, I don't have any idea at all.
Here's my code. I modified from this one http://www.mathworks.com/products/demos/image/cross_correlation/imreg.html
onion = imread('pattern103.jpg'); %pattern image
peppers = imread('rsz_1jib-159.jpg'); %Original image
onion = rgb2gray(onion);
peppers = rgb2gray(peppers);
%imshow(onion)
%figure, imshow(peppers)
c = normxcorr2(onion,peppers);
figure, surf(c), shading flat
% offset found by correlation
[max_c, imax] = max(abs(c(:)));
[ypeak, xpeak] = ind2sub(size(c),imax(1));
corr_offset = [(xpeak-size(onion,2))
(size(onion,1)-ypeak)]; %size of window show of max value
offset = corr_offset;
xoffset = offset(1);
yoffset = offset(2);
xbegin = round(xoffset+1); fprintf(['xbegin = ',num2str(xbegin)]);fprintf('\n');
xend = round(xoffset+ size(onion,2));fprintf(['xend = ',num2str(xbegin)]);fprintf('\n');
ybegin = round(yoffset+1);fprintf(['ybegin = ',num2str(ybegin)]);fprintf('\n');
yend = round(yoffset+size(onion,1));fprintf(['yend = ',num2str(yend)]);fprintf('\n');
% extract region from peppers and compare to onion
extracted_onion = peppers(ybegin:yend,xbegin:xend,:);
if isequal(onion,extracted_onion)
disp('pattern103.jpg was extracted from rsz_org103.jpg')
end
recovered_onion = uint8(zeros(size(peppers)));
recovered_onion(ybegin:yend,xbegin:xend,:) = onion;
figure, imshow(recovered_onion)
[m,n,p] = size(peppers);
mask = ones(m,n);
i = find(recovered_onion(:,:,1)==0);
mask(i) = .2; % try experimenting with different levels of
% transparency
% overlay images with transparency
figure, imshow(peppers(:,:,1)) % show only red plane of peppers
hold on
h = imshow(recovered_onion); % overlay recovered_onion
set(h,'AlphaData',mask)

Resources