To show/join Two Images Simultaneously in Matlab's slider? - image

I cannot make too big file (like tried here) so I need to show only portions at a time.
However, I cannot make the transfer from one file to another smooth in Matlab.
I am trying to expand the solution of the thread To refresh imshow in Matlab? for two images. The problem is the ending of image A and start of the image B. Now, I have an interruption in the flow, which I do not like because I cannot show two images at the same time without an interruption.
In the example here, it is not needed to filter the axes.
Code
iterationCounter=1;
hFig=figure('Menubar','none', 'NumberTitle','off', 'Color','k');
while(iterationCounter < 7)
filenamePng=fullfile(homedir, '/Images/Raw/', iterationCounter, '.png');
imgRGB=imread(filenamePng);
% https://stackoverflow.com/a/29952648/54964
%%// create sliding-window video
len = 40*2^3;
signal = imgRGB(:,1:end,:);
hImg = imshow(signal(:,1:1+len,:), ...
'InitialMagnification',100, 'Border','tight');
vid = VideoWriter('signal.avi');
vid.Quality = 100;
vid.FrameRate = 60;
open(vid);
M = size(signal,2);
for k=1:M-len
set(hImg, 'CData',signal(:,k:k+len,:))
writeVideo(vid, getframe());
end
iterationCounter=iterationCounter+1;
end
close(vid);
Output for Image A and Image B
where there is an interruption in the slider after each image.
The picture is just a screenshot of two images: beginning and ending of the slider. The blue area is just OS X GUI but still indicates that there is a gap and interruption between the start and end.
How can show/join two images simultaneously in Matlab's slider?

In order to display multiple images side by side in this scrolling window, I think the easiest approach is to actually load all of the images upfront into an array that is [nRows x (nColumns * nImages) x 3] and then just use the original code to scroll through this.
hFig=figure('Menubar','none', 'NumberTitle','off', 'Color','k');
signal = [];
% Load all the images into one "long" image
for k = 1:7
filename = fullfile(homedir, sprintf('%d.png', k));
img = imread(filename);
signal = cat(2, signal, img);
end
%%// create sliding-window video
windowWidth = 320; % Width in pixels
hImg = imshow(signal(:,1:1 + windowWidth,:), ...
'InitialMagnification',100, 'Border','tight');
vid = VideoWriter('signal.avi');
vid.Quality = 100;
vid.FrameRate = 60;
open(vid);
M = size(signal,2);
for k = 1:(M - windowWidth)
set(hImg, 'CData',signal(:,k:k + windowWidth,:))
writeVideo(vid, getframe());
end
close(vid);

The command imagesc is a low-level image command where Suever's proposal does not work.
A general approach to remove padding/margins/background is to use
<plot imshow imagesc ...>
set(gca,'position',[0 0 1 1],'units','normalized')

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.

How to show all the lines I draw by imfreehand

I am using a code that allows me to draw freehand on the image. The code is as below:
I = imread('peppers.png');
imshow(I);
for i=1:3
M = imfreehand(gca,'Closed',0);
F = false(size(M.createMask));
end
P0 = M.getPosition;
D = round([0; cumsum(sum(abs(diff(P0)),2))]);
P = interp1(D,P0,D(1):.5:D(end));
P = unique(round(P),'rows');
S = sub2ind(size(I),P(:,2),P(:,1));
F(S) = true;
figure;
imshow(F);
imwrite(F,'line.jpg')
Picture 1
Picture 2
Using above code, I can draw freehand as I wish on the photo (Picture 1). But in the output figure (Picture 2), it shows only the last figure I've drawn. I want to show all freehand figures that I've drawn. Can anyone suggest me how shall I improve the codes so whatever I draw on pic1 will be shown on pic2. Thanks.
It's simply a matter of the end of your loop (i.e. the end syntax) so that you are setting the mask after each iteration. What you are doing instead is capturing all of the strokes, but you are resetting the mask that contains the stroke at each iteration. Therefore you only capture the stroke of the last iteration.
You'll need to fix this and once you do, you will also need an external mask variable that remembers each stroke as you make it then this is the final mask variable you save in the end.
My edits to your code are seen below delineated in comments:
close all;
I = imread('peppers.png');
figure;
imshow(I);
%// New - Create external mask variable that remembers each stroke in the loop
mask = false(size(I,1), size(I,2));
for i=1:3
M = imfreehand(gca,'Closed',0);
F = false(size(M.createMask));
P0 = M.getPosition;
D = round([0; cumsum(sum(abs(diff(P0)),2))]);
P = interp1(D,P0,D(1):.5:D(end));
P = unique(round(P),'rows');
S = sub2ind(size(I),P(:,2),P(:,1));
F(S) = true;
%// Save stroke into external mask
mask = mask | F;
end %// Move end statement here
%// Show mask then save
figure;
imshow(mask);
imwrite(mask,'line.jpg');
The logical OR operation (i.e. |) updates the mask with each stroke as you loop through and make new ones. When I make the above modifications, I now get this image when I tried to replicate your strokes right before it gets saved:

Separating Background and Foreground

I am new to Matlab and to Image Processing as well. I am working on separating background and foreground in images like this
I have hundreds of images like this, found here. By trial and error I found out a threshold (in RGB space): the red layer is always less than 150 and the green and blue layers are greater than 150 where the background is.
so if my RGB image is I and my r,g and b layers are
redMatrix = I(:,:,1);
greenMatrix = I(:,:,2);
blueMatrix = I(:,:,3);
by finding coordinates where in red, green and blue the values are greater or less than 150 I can get the coordinates of the background like
[r1 c1] = find(redMatrix < 150);
[r2 c2] = find(greenMatrix > 150);
[r3 c3] = find(blueMatrix > 150);
now I get coordinates of thousands of pixels in r1,c1,r2,c2,r3 and c3.
My questions:
How to find common values, like the coordinates of the pixels where red is less than 150 and green and blue are greater than 150?
I have to iterate every coordinate of r1 and c1 and check if they occur in r2 c2 and r3 c3 to check it is a common point. but that would be very expensive.
Can this be achieved without a loop ?
If somehow I came up with common points like [commonR commonC] and commonR and commonC are both of order 5000 X 1, so to access this background pixel of Image I, I have to access first commonR then commonC and then access image I like
I(commonR(i,1),commonC(i,1))
that is expensive too. So again my question is can this be done without loop.
Any help would be appreciated.
I got solution with #Science_Fiction answer's
Just elaborating his/her answer
I used
mask = I(:,:,1) < 150 & I(:,:,2) > 150 & I(:,:,3) > 150;
No loop is needed. You could do it like this:
I = imread('image.jpg');
redMatrix = I(:,:,1);
greenMatrix = I(:,:,2);
blueMatrix = I(:,:,3);
J(:,:,1) = redMatrix < 150;
J(:,:,2) = greenMatrix > 150;
J(:,:,3) = blueMatrix > 150;
J = 255 * uint8(J);
imshow(J);
A greyscale image would also suffice to separate the background.
K = ((redMatrix < 150) + (greenMatrix > 150) + (blueMatrix > 150))/3;
imshow(K);
EDIT
I had another look, also using the other images you linked to.
Given the variance in background colors, I thought you would get better results deriving a threshold value from the image histogram instead of hardcoding it.
Occasionally, this algorithm is a little to rigorous, e.g. erasing part of the clothes together with the background. But I think over 90% of the images are separated pretty well, which is more robust than what you could hope to achieve with a fixed threshold.
close all;
path = 'C:\path\to\CUHK_training_cropped_photos\photos';
files = dir(path);
bins = 16;
for f = 3:numel(files)
fprintf('%i/%i\n', f, numel(files));
file = files(f);
if isempty(strfind(file.name, 'jpg'))
continue
end
I = imread([path filesep file.name]);
% Take the histogram of the blue channel
B = I(:,:,3);
h = imhist(B, bins);
h2 = h(bins/2:end);
% Find the most common bin in the *upper half*
% of the histogram
m = bins/2 + find(h2 == max(h2));
% Set the threshold value somewhat below
% the value corresponding to that bin
thr = m/bins - .25;
BW = im2bw(B, thr);
% Pad with ones to ensure background connectivity
BW = padarray(BW, [1 1], 1);
% Find connected regions in BW image
CC = bwconncomp(BW);
L = labelmatrix(CC);
% Crop back again
L = L(2:end-1,2:end-1);
% Set the largest region in the orignal image to white
for c = 1:3
channel = I(:,:,c);
channel(L==1) = 255;
I(:,:,c) = channel;
end
% Show the results with a pause every 16 images
subplot(4,4,mod(f-3,16)+1);
imshow(I);
title(sprintf('Img %i, thr %.3f', f, thr));
if mod(f-3,16)+1 == 16
pause
clf
end
end
pause
close all;
Results:
Your approach seems basic but decent. Since for this particular image the background is composed of mainly blue so you be crude and do:
mask = img(:,:,3) > 150;
This will set those pixels which evaluate to true for > 150 to 0 and false to 1. You will have a black and white image though.
imshow(mask);
To add colour back
mask3d(:,:,1) = mask;
mask3d(:,:,2) = mask;
mask3d(:,:,3) = mask;
img(mask3d) = 255;
imshow(img);
Should give you the colour image of face hopefully, with a pure white background. All this requires some trial and error.

Playing image sequences in MATLAB

Greetings to all of you.
I have this somewhat frustrating problem, and I hope that you kindly help me solve it.
I am developing a human tracking system in MATLAB, and would like to show the result in an appealing GUI (also in MATLAB using GUIDE).
There is this main window where an image sequence of about 2500 gray scale images of size 320x240 would be played like a video but where the humans be outlined in them nicely.
The challenge is; these images need a bit of processing (detection outlining of humans) before being shown on the window.
Now, is it possible to display a set of images while at the same time do some processing for another set to be shown afterwards?
I would very much prefer it to play like a normal video, but I guess that would be somehow ambitious.
Here is an example showing a scenario similar to what you described. This was adapted from the demo I mentioned in the comments.
function ImgSeqDemo()
figure()
for i=1:10
%# read image
img = imread( sprintf('AT3_1m4_%02d.tif',i) );
%# process image to extract some object of interest
[BW,rect] = detectLargestCell(img);
%# show image
imshow(img), hold on
%# overlay mask in red color showing object
RGB = cat(3, BW.*255, zeros(size(BW),'uint8'), zeros(size(BW),'uint8'));
hImg = imshow(RGB); set(hImg, 'AlphaData',0.5);
%# show bounding rectangle
rectangle('Position', rect, 'EdgeColor','g');
hold off
drawnow
end
end
Here is the processing function used above. In your case, you would insert your algorithm instead:
function [BW,rect] = detectLargestCell(I)
%# OUTPUT
%# BW binary mask of largest detected cell
%# rect bounding box of largest detected cell
%# find components
[~, threshold] = edge(I, 'sobel');
BW = edge(I,'sobel', threshold*0.5);
se90 = strel('line', 3, 90);
se0 = strel('line', 3, 0);
BW = imdilate(BW, [se90 se0]);
BW = imclearborder(BW, 4);
BW = bwareaopen(BW, 200);
BW = bwmorph(BW, 'close');
BW = imfill(BW, 'holes');
%# keep largest component
CC = bwconncomp(BW);
stats = regionprops(CC, {'Area','BoundingBox'});
[~,idx] = max([stats.Area]);
rect = stats(idx).BoundingBox;
BW(:) = 0;
BW(CC.PixelIdxList{idx}) = 1;
end

Resources