MATLAB: Finding minimal pixel values from a video - matlab

I'm trying to write some MATLAB code such that given a monochromatic video, It needs to produce a image such that each pixel of the image equals the minimal value that said pixel takes in the video. As an example the pixel (200,300) will equal the min value that pixel (200,300) through the course of the video. I have written some code to do this however it's terribly inefficient. Any comments to improve my code would be appriciated
hologramVideo = VideoReader('test.mp4')
mkdir('images')
frames = int16(hologramVideo.Duration * hologramVideo.FrameRate)
imageValues = cell(frames, 1);
ii = 1;
while hasFrame(hologramVideo)
imageValues{ii} = im2uint8(rgb2gray(readFrame(hologramVideo)));
ii = ii + 1;
end
newImage = zeros(512)
currentMin = 255
currentVal = 0
x = 1;
y = 1;
for x = 1:512
for y = 1:512
currentMin = 0;
for i = 1:frames
currentImg = imageValues(i,1,1);
currentVal = currentImg{1,1}(x,y)
if currentVal < currentMin;
currentMin = currentVal;
end
end
newImage(x,y) = currentMin;
end
end

I don't have a file to test, but the main bottleneck is in how you store the images. Rather than storing them in a cell array, you are better off storing them in a 3D-array:
imageValues = zeros([Nframes, 512, 512]);
ii=1;
while hasFrame(hologramVideo)
imageValues(ii,:,:) = im2uint8(rgb2gray(readFrame(hologramVideo)));
ii = ii + 1;
end
That would make the remainder of the code very easy and vectorized (i.e. fast):
newImage = squeeze(min(imageValues,[],1));

Related

Im trying to hide an image inside another using LSB but the resulting image is Coming out with high contrast

hello i wrote a simple code using a simple algorithm to understand steganography better , using LSB i hide the pixel values of one image into another, the key in this case represents the amount of steps (pixels) the loop will take to hide consecutive pixels from the secret cat image into the tree image.
I know it's not very secure but that's not the point.
My code to hide image:
% Function that accepts dir for secret image and dir for image to hide it in
% it writes an image that contains the secret image.
% it return an array containing the dimensions of the secret image
% because we need them in the revealing function
function [dim] = hideMyimg(secret,image,Key)
img = imread(image);
egg = imread(secret);
% Setting the least significant bits to zero
img = img - mod(img,4);
%checking if the secret fits into the hiding place
img = check(img,egg);
dim = [size(egg,1),size(egg,2)];
% using modulus to lower the amount of steps, to simplify code
key = mod(Key,1000);
%Seperating color channels
r1 = img(:,:,1);
g1 = img(:,:,2);
b1 = img(:,:,3);
r2 = egg(:,:,1);
g2 = egg(:,:,2);
b2 = egg(:,:,3);
%Driver code
r = hide(r1,r2,key);
g = hide(g1,g2,key);
b = hide(b1,b2,key);
%Combining the color channels
output(:,:,1) = r;
output(:,:,2) = g;
output(:,:,3) = b;
imwrite(output,'output.png')
end
%Function to hid matrix inside another
function [hidden] = hide(image,egg,key)
[row,col] = size(egg);
% turning the matrices into vectors to make it easy to loop over
imgvec = image(:);
% Move the most significant bits of the secret image to the least significant bits
tempi = egg./64;
eggvec = tempi(:);
%max value of pixels to hide
max = row*col;
% counter to make sure the loop stops once all the pixels are hidden
i = 1;
% temp value we need to re-loop over the matrix from a new starting point
temp = 2;
%counter
n = 1;
while(i<max)
imgvec(n) = imgvec(n) + eggvec(i);
n = n + key;
if n>max
n = temp;
temp = temp + 1;
end
i = i + 1;
end
hidden = reshape(imgvec,[size(image,1),size(image,2)]);
end
% Function to check if image 1 is bigger than image 2
% And if so resize image 1 to be bigger than image 2
function [image] = check(img1,img2)
row1 = size(img1,1);
col1 = size(img1,2);
row2 = size(img2,1);
col2 = size(img2,2);
if row2*col2>row1*col1
val1 = ceil(row2/row1);
val2 = ceil(col2/col1);
if val1 > val2
image = imresize(img1,val1);
else
image = imresize(img1,val2);
end
else
image = img1;
disp('yes')
end
end
code to reveal image hidden:
function [] = getMyimg(key,dim)
image = imread('output.png');
%seperating color channels
r = image(:,:,1);
g = image(:,:,2);
b = image(:,:,3);
row = dim(1);
col = dim(2);
egg(:,:,1) = getimg(r,key,row,col);
egg(:,:,2) = getimg(g,key,row,col);
egg(:,:,3) = getimg(b,key,row,col);
% move least significant bits to the most significant
egg = egg * 64;
imwrite(egg,'secret.png');
end
function [egg] = getimg(image,key,row,col)
imgvec = image(:);
%initializing vector with the right dimensions for the secret image
eggvec = zeros(row*col,1);
max = row*col;
i = 1;
n = 1;
temp = 2;
while i < max
%get the least significant bits
eggvec(i) = mod(imgvec(n),4);
n = n + key;
if n>max
n = temp;
temp = temp + 1;
end
i = i + 1;
end
egg = reshape(eggvec,[row,col]);
end
resulting image:
why is it coming out like this?

Local Interest Point Detection using Difference of Gaussian in Matlab

I'm writing the code in Matlab to find interest point using DoG in the image.
Here is the main.m:
imTest1 = rgb2gray(imread('1.jpg'));
imTest1 = double(imTest1);
sigma = 0.6;
k = 5;
thresh = 3;
[x1,y1,r1] = DoG(k,sigma,thresh,imTest1);
%get the interest points and show it on the image with its scale
figure(1);
imshow(imTest1,[]), hold on, scatter(y1,x1,r1,'r');
And the function DoG is:
function [x,y,r] = DoG(k,sigma,thresh,imTest)
x = []; y = []; r = [];
%suppose 5 levels of gaussian blur
for i = 1:k
g{i} = fspecial('gaussian',size(imTest),i*sigma);
end
%so 4 levels of DoG
for i = 1:k-1
d{i} = imfilter(imTest,g{i+1}-g{i});
end
%compare the current pixel in the image to the surrounding pixels (26 points),if it is the maxima/minima, this pixel will be a interest point
for i = 2:k-2
for m = 2:size(imTest,1)-1
for n = 2:size(imTest,2)-1
id = 1;
compare = zeros(1,27);
for ii = i-1:i+1
for mm = m-1:m+1
for nn = n-1:n+1
compare(id) = d{ii}(mm,nn);
id = id+1;
end
end
end
compare_max = max(compare);
compare_min = min(compare);
if (compare_max == d{i}(m,n) || compare_min == d{i}(m,n))
if (compare_min < -thresh || compare_max > thresh)
x = [x;m];
y = [y;n];
r = [r;abs(d{i}(m,n))];
end
end
end
end
end
end
So there's a gaussian function and the sigma i set is 0.6. After running the code, I find the position is not correct and the scales looks almost the same for all interest points. I think my code should work but actually the result is not. Anybody know what's the problem?

How to reduce the time consumed by the for loop?

I am trying to implement a simple pixel level center-surround image enhancement. Center-surround technique makes use of statistics between the center pixel of the window and the surrounding neighborhood as a means to decide what enhancement needs to be done. In the code given below I have compared the center pixel with average of the surrounding information and based on that I switch between two cases to enhance the contrast. The code that I have written is as follows:
im = normalize8(im,1); %to set the range of pixel from 0-255
s1 = floor(K1/2); %K1 is the size of the window for surround
M = 1000; %is a constant value
out1 = padarray(im,[s1,s1],'symmetric');
out1 = CE(out1,s1,M);
out = (out1(s1+1:end-s1,s1+1:end-s1));
out = normalize8(out,0); %to set the range of pixel from 0-1
function [out] = CE(out,s,M)
B = 255;
out1 = out;
for i = s+1 : size(out,1) - s
for j = s+1 : size(out,2) - s
temp = out(i-s:i+s,j-s:j+s);
Yij = out1(i,j);
Sij = (1/(2*s+1)^2)*sum(sum(temp));
if (Yij>=Sij)
Aij = A(Yij-Sij,M);
out1(i,j) = ((B + Aij)*Yij)/(Aij+Yij);
else
Aij = A(Sij-Yij,M);
out1(i,j) = (Aij*Yij)/(Aij+B-Yij);
end
end
end
out = out1;
function [Ax] = A(x,M)
if x == 0
Ax = M;
else
Ax = M/x;
end
The code does the following things:
1) Normalize the image to 0-255 range and pad it with additional elements to perform windowing operation.
2) Calls the function CE.
3) In the function CE obtain the windowed image(temp).
4) Find the average of the window (Sij).
5) Compare the center of the window (Yij) with the average value (Sij).
6) Based on the result of comparison perform one of the two enhancement operation.
7) Finally set the range back to 0-1.
I have to run this for multiple window size (K1,K2,K3, etc.) and the images are of size 1728*2034. When the window size is selected as 100, the time consumed is very high.
Can I use vectorization at some stage to reduce the time for loops?
The profiler result (for window size 21) is as follows:
The profiler result (for window size 100) is as follows:
I have changed the code of my function and have written it without the sub-function. The code is as follows:
function [out] = CE(out,s,M)
B = 255;
Aij = zeros(1,2);
out1 = out;
n_factor = (1/(2*s+1)^2);
for i = s+1 : size(out,1) - s
for j = s+1 : size(out,2) - s
temp = out(i-s:i+s,j-s:j+s);
Yij = out1(i,j);
Sij = n_factor*sum(sum(temp));
if Yij-Sij == 0
Aij(1) = M;
Aij(2) = M;
else
Aij(1) = M/(Yij-Sij);
Aij(2) = M/(Sij-Yij);
end
if (Yij>=Sij)
out1(i,j) = ((B + Aij(1))*Yij)/(Aij(1)+Yij);
else
out1(i,j) = (Aij(2)*Yij)/(Aij(2)+B-Yij);
end
end
end
out = out1;
There is a slight improvement in the speed from 93 sec to 88 sec. Suggestions for any other improvements to my code are welcomed.
I have tried to incorporate the suggestions given to replace sliding window with convolution and then vectorize the rest of it. The code below is my implementation and I'm not getting the result expected.
function [out_im] = CE_conv(im,s,M)
B = 255;
temp = ones(2*s,2*s);
temp = temp ./ numel(temp);
out1 = conv2(im,temp,'same');
out_im = im;
Aij = im-out1; %same as Yij-Sij
Aij1 = out1-im; %same as Sij-Yij
Mij = Aij;
Mij(Aij>0) = M./Aij(Aij>0); % if Yij>Sij Mij = M/Yij-Sij;
Mij(Aij<0) = M./Aij1(Aij<0); % if Yij<Sij Mij = M/Sij-Yij;
Mij(Aij==0) = M; % if Yij-Sij == 0 Mij = M;
out_im(Aij>=0) = ((B + Mij(Aij>=0)).*im(Aij>=0))./(Mij(Aij>=0)+im(Aij>=0));
out_im(Aij<0) = (Mij(Aij<0).*im(Aij<0))./ (Mij(Aij<0)+B-im(Aij<0));
I am not able to figure out where I'm going wrong.
A detailed explanation of what I'm trying to implement is given in the following paper:
Vonikakis, Vassilios, and Ioannis Andreadis. "Multi-scale image contrast enhancement." In Control, Automation, Robotics and Vision, 2008. ICARCV 2008. 10th International Conference on, pp. 856-861. IEEE, 2008.
I've tried to see if I could get those times down by processing with colfiltand nlfilter, since both are usually much faster than for-loops for sliding window image processing.
Both worked fine for relatively small windows. For an image of 2048x2048 pixels and a window of 10x10, the solution with colfilt takes about 5 seconds (on my personal computer). With a window of 21x21 the time jumped to 27 seconds, but that is still a relative improvement on the times displayed on the question. Unfortunately I don't have enough memory to colfilt using windows of 100x100, but the solution with nlfilter works, though taking about 120 seconds.
Here the code
Solution with colfilt:
function outval = enhancematrix(inputmatrix,M,B)
%Inputmatrix is a 2D matrix or column vector, outval is a 1D row vector.
% If inputmatrix is made of integers...
inputmatrix = double(inputmatrix);
%1. Compute S and Y
normFactor = 1 / (size(inputmatrix,1) + 1).^2; %Size of column.
S = normFactor*sum(inputmatrix,1); % Sum over the columns.
Y = inputmatrix(ceil(size(inputmatrix,1)/2),:); % Center row.
% So far we have all S and Y, one value per column.
%2. Compute A(abs(Y-S))
A = Afunc(abs(S-Y),M);
% And all A: one value per column.
%3. The tricky part. If Y(i)-S(i) > 0 do something.
doPositive = (Y > S);
doNegative = ~doPositive;
outval = zeros(1,size(inputmatrix,2));
outval(doPositive) = (B + A(doPositive) .* Y(doPositive)) ./ (A(doPositive) + Y(doPositive));
outval(doNegative) = (A(doNegative) .* Y(doNegative)) ./ (A(doNegative) + B - Y(doNegative));
end
function out = Afunc(x,M)
% Input x is a row vector. Output is another row vector.
out = x;
out(x == 0) = M;
out(x ~= 0) = M./x(x ~= 0);
end
And to call it, simply do:
M = 1000; B = 255; enhancenow = #(x) enhancematrix(x,M,B);
w = 21 % windowsize
result = colfilt(inputImage,[w w],'sliding',enhancenow);
Solution with nlfilter:
function outval = enhanceimagecontrast(neighbourhood,M,B)
%1. Compute S and Y
normFactor = 1 / (length(neighbourhood) + 1).^2;
S = normFactor*sum(neighbourhood(:));
Y = neighbourhood(ceil(size(neighbourhood,1)/2),ceil(size(neighbourhood,2)/2));
%2. Compute A(abs(Y-S))
test = (Y>=S);
A = Afunc(abs(Y-S),M);
%3. Return outval
if test
outval = ((B + A) * Y) / (A + Y);
else
outval = (A * Y) / (A + B - Y);
end
function aval = Afunc(x,M)
if (x == 0)
aval = M;
else
aval = M/x;
end
And to call it, simply do:
M = 1000; B = 255; enhancenow = #(x) enhanceimagecontrast(x,M,B);
w = 21 % windowsize
result = nlfilter(inputImage,[w w], enhancenow);
I didn't spend much time checking that everything is 100% correct, but I did see some nice contrast enhancement (hair looks particularly nice).
This answer is the implementation that was suggested by Peter. I debugged the implementation and presenting the final working version of the fast implementation.
function [out_im] = CE_conv(im,s,M)
B = 255;
im = ( im - min(im(:)) ) ./ ( max(im(:)) - min(im(:)) )*255;
h = ones(s,s)./(s*s);
out1 = imfilter(im,h,'conv');
out_im = im;
Aij = im-out1; %same as Yij-Sij
Aij1 = out1-im; %same as Sij-Yij
Mij = Aij;
Mij(Aij>0) = M./Aij(Aij>0); % if Yij>Sij Mij = M/(Yij-Sij);
Mij(Aij<0) = M./Aij1(Aij<0); % if Yij<Sij Mij = M/(Sij-Yij);
Mij(Aij==0) = M; % if Yij-Sij == 0 Mij = M;
out_im(Aij>=0) = ((B + Mij(Aij>=0)).*im(Aij>=0))./(Mij(Aij>=0)+im(Aij>=0));
out_im(Aij<0) = (Mij(Aij<0).*im(Aij<0))./ (Mij(Aij<0)+B-im(Aij<0));
out_im = ( out_im - min(out_im(:)) ) ./ ( max(out_im(:)) - min(out_im(:)) );
To call this use the following code
I = imread('pout.tif');
w_size = 51;
M = 4000;
output = CE_conv(I(:,:,1),w_size,M);
The output for the 'pout.tif' image is given below
The execution time for Bigger image and with 100*100 block size is around 5 secs with this implementation.

Change input video from saved video to streaming video for manipulation

I downloaded this code from MIT's video magnification lab: http://people.csail.mit.edu/mrub/evm/#code
Except it currently only runs on saved videos. We wanted to change it so that we can have a live video set up.
The matlab code is as follows:
dataDir = './data';
resultsDir = 'ResultsSIGGRAPH2012';
mkdir(resultsDir);
inFile = fullfile(dataDir,'face2.mp4');
fprintf('Processing %s\n', inFile);
% Motion
amplify_spatial_lpyr_temporal_butter(inFile,resultsDir,20,80, ...
0.5,10,30, 0);
The amplify_spatial_lpyr_temporal_butter matlab code is:
function amplify_spatial_lpyr_temporal_butter(vidFile, outDir ...
,alpha, lambda_c, fl, fh ...
,samplingRate, chromAttenuation)
[low_a, low_b] = butter(1, fl/samplingRate, 'low');
[high_a, high_b] = butter(1, fh/samplingRate, 'low');
[~,vidName] = fileparts(vidFile);
outName = fullfile(outDir,[vidName '-butter-from-' num2str(fl) '-to-' ...
num2str(fh) '-alpha-' num2str(alpha) '-lambda_c-' num2str(lambda_c) ...
'-chromAtn-' num2str(chromAttenuation) '.avi']);
% Read video
vid = VideoReader(vidFile);
% Extract video info
vidHeight = vid.Height;
vidWidth = vid.Width;
nChannels = 3;
fr = vid.FrameRate;
len = vid.NumberOfFrames;
temp = struct('cdata', ...
zeros(vidHeight, vidWidth, nChannels, 'uint8'), ...
'colormap', []);
startIndex = 1;
endIndex = len-10;
vidOut = VideoWriter(outName);
vidOut.FrameRate = fr;
open(vidOut)
% firstFrame
temp.cdata = read(vid, startIndex);
[rgbframe,~] = frame2im(temp);
rgbframe = im2double(rgbframe);
frame = rgb2ntsc(rgbframe);
[pyr,pind] = buildLpyr(frame(:,:,1),'auto');
pyr = repmat(pyr,[1 3]);
[pyr(:,2),~] = buildLpyr(frame(:,:,2),'auto');
[pyr(:,3),~] = buildLpyr(frame(:,:,3),'auto');
lowpass1 = pyr;
lowpass2 = pyr;
pyr_prev = pyr;
output = rgbframe;
writeVideo(vidOut,im2uint8(output));
nLevels = size(pind,1);
for i=startIndex+1:endIndex
progmeter(i-startIndex,endIndex - startIndex + 1);
temp.cdata = read(vid, i);
[rgbframe,~] = frame2im(temp);
rgbframe = im2double(rgbframe);
frame = rgb2ntsc(rgbframe);
[pyr(:,1),~] = buildLpyr(frame(:,:,1),'auto');
[pyr(:,2),~] = buildLpyr(frame(:,:,2),'auto');
[pyr(:,3),~] = buildLpyr(frame(:,:,3),'auto');
%% temporal filtering
lowpass1 = (-high_b(2) .* lowpass1 + high_a(1).*pyr + ...
high_a(2).*pyr_prev)./high_b(1);
lowpass2 = (-low_b(2) .* lowpass2 + low_a(1).*pyr + ...
low_a(2).*pyr_prev)./low_b(1);
filtered = (lowpass1 - lowpass2);
pyr_prev = pyr;
%% amplify each spatial frequency bands according to Figure 6 of our paper
ind = size(pyr,1);
delta = lambda_c/8/(1+alpha);
% the factor to boost alpha above the bound we have in the
% paper. (for better visualization)
exaggeration_factor = 2;
% compute the representative wavelength lambda for the lowest spatial
% freqency band of Laplacian pyramid
lambda = (vidHeight^2 + vidWidth^2).^0.5/3; % 3 is experimental constant
for l = nLevels:-1:1
indices = ind-prod(pind(l,:))+1:ind;
% compute modified alpha for this level
currAlpha = lambda/delta/8 - 1;
currAlpha = currAlpha*exaggeration_factor;
if (l == nLevels || l == 1) % ignore the highest and lowest frequency band
filtered(indices,:) = 0;
elseif (currAlpha > alpha) % representative lambda exceeds lambda_c
filtered(indices,:) = alpha*filtered(indices,:);
else
filtered(indices,:) = currAlpha*filtered(indices,:);
end
ind = ind - prod(pind(l,:));
% go one level down on pyramid,
% representative lambda will reduce by factor of 2
lambda = lambda/2;
end
%% Render on the input video
output = zeros(size(frame));
output(:,:,1) = reconLpyr(filtered(:,1),pind);
output(:,:,2) = reconLpyr(filtered(:,2),pind);
output(:,:,3) = reconLpyr(filtered(:,3),pind);
output(:,:,2) = output(:,:,2)*chromAttenuation;
output(:,:,3) = output(:,:,3)*chromAttenuation;
output = frame + output;
output = ntsc2rgb(output);
% filtered = rgbframe + filtered.*mask;
output(output > 1) = 1;
output(output < 0) = 0;
writeVideo(vidOut,im2uint8(output));
end
close(vidOut);
end
We are trying to get it to work with a streaming video input, but don't really know where to start. We are somewhat familiar with programming but not so familiar with Matlab and so don't really know where to look for such answers.
Any help would be greatly appreciated.

Using Heat Equation to blur images using Matlab

I am trying to use the PDE heat equation and apply it to images using Matlab. The problem i am having is that the image isn't blurring , it is just going white. Also, I am getting different results from the rest of the class who is using Maple.
Here is the code:
% George Lees Jr.
% Heat equation
clear,clc;
dx = 1;
dy = 1;
dt = .025;
%dt/(dx*dx)
t = 0;
time = 3;
T_old = imread('tulipgray.jpg');
T_temp=T_old;
[m,n,k] = size(T_temp);
%colormap gray;
%imagesc(T_temp);
%imshow(T_old);
T_new = T_temp;
T_new=ind2gray(T_new,colormap);
%T_new(:,50)=0;
%T_old(1,70)
%imagesc(T_new);
%diff_x = dt/(dx*dx)
%diff_y = dt/ (dy*dy)
%time = 0;
while t < time
for i = 2:1:m-1
for j = 2:1:n-1
T_new(i,j) = T_temp(i,j) + dt*(T_temp(i+1,j) -2*T_temp(i,j) + T_temp(i-1,j)) + dt*(T_temp(i,j+1)-2*T_temp(i,j) + T_temp(i,j-1));
t = t+dt;
T_temp(i,j) = T_new(i,j);
end
end
end
figure
imshow(T_new)
Yeah the image just gets whiter
There's 2 issues with your code:
1) you're incrementing the time counter after each individual pixel instead of after doing the whole image
2) you need to do the calculations on floating points values, not integers. dt is small, so the values from the RHS of the equation are <1
Fixed code should look something like this
clear,clc;
dt = 0.025;
time = 3;
T_old = imread('rice.png');
T_temp=double(T_old);
[m,n,k] = size(T_temp);
T_new = double(T_temp);
T_new=ind2gray(T_new,colormap);
while t < time
for i = 2:1:m-1
for j = 2:1:n-1
T_new(i,j) = T_temp(i,j) + dt*(T_temp(i+1,j) -2*T_temp(i,j) + T_temp(i-1,j)) + dt*(T_temp(i,j+1)-2*T_temp(i,j) + T_temp(i,j-1));
end
end
T_temp = T_new;
t = t+dt;
imshow(uint8(T_new))
getframe;
end