how to use colfilt\ bloc_proc my own function - matlab

I'm trying to use colfilt but instead using one line function I want to apply some condition, for example:
I2 = colfilt(I,[50 50],'sliding',own_func);
function own_func(block_struct)
mean(block_struct.data);
if(block_struct.data<6000)
block_struct.data=0;
else block_struct.data=255;
end
end
Is that possible?

function foo()
I = imread('tire.tif');
function y = complicated_function(x)
%column to number
y=mean(x);
end
I2 = uint8(colfilt(I,[5 5],'sliding',#complicated_function));
end

Related

Generate random matrix with eigenvalues

I am doing the following to generate random matrices with eigenvalues in a specific range:
function mat = randEig(dim, rReal)
D=diff(rReal).*rand(dim,1)+rReal(1);
P=rand(dim);
mat=P*diag(D)/P;
end
But I also want to be able to generate random real matrices with complex (conjugate) eigenvalues. How would one do that? The similarity transformation trick would return complex matrices.
EDIT: Okay I managed to do it by piggybacking on MATLAB's cdf2rdf function (which is basically the second function below).
function mat = randEig(dim, rangeEig, nComplex)
if 2*nComplex > dim
error('Cannot happen');
end
if nComplex
cMat=diff(rangeEig).*rand(dim-2*nComplex,1)+rangeEig(1);
for k=1:nComplex
rpart=(diff(rangeEig).*rand(1,1)+rangeEig(1))*ones(2,1);
ipart=(diff(rangeEig).*rand(1,1)+rangeEig(1))*i;
ipart=[ipart; -ipart];
cMat=[cMat; rpart+ipart];
end
else
cMat=diff(rangeEig).*rand(dim,1)+rangeEig(1);
end
D=cMat;
realDform = comp2rdf(diag(D));
P=rand(dim);
mat=P*realDform/P;
end
function dd = comp2rdf(d)
i = find(imag(diag(d))');
index = i(1:2:length(i));
if isempty(index)
dd=d;
else
if (max(index)==size(d,1)) | any(conj(d(index,index))~=d(index+1,index+1))
error(message('Complex conjugacy not satisfied'));
end
j = sqrt(-1);
t = eye(length(d));
twobytwo = [1 1;j -j];
for i=index
t(i:i+1,i:i+1) = twobytwo;
end
dd=t*d/t;
end
end
But the code is ugly, mainly the way rand is called multiple times is annoying). If someone wants to post an answer that calls rand once and manages to do the trick I will surely accept and upvote.
I made it either a single call or two calls with this:
function mat = randEig(dim, rangeEig, nComplex)
if 2*nComplex > dim
error('Cannot happen');
end
if nComplex
cMat=diff(rangeEig).*rand(2*nComplex,1)+rangeEig(1);
cPart=cMat(1:nComplex)*i;
cMat(1:nComplex)=[];
cPart=upsample(cPart,2);
cPart=cPart+circshift(-cPart,1);
cMat=upsample(cMat,2);
cMat=cMat+circshift(cMat,1);
cMat=cMat+cPart;
cMat=[diff(rangeEig).*rand(dim-2*nComplex,1)+rangeEig(1); cMat];
else
cMat=diff(rangeEig).*rand(dim,1)+rangeEig(1);
end
D=cMat;
realDform = comp2rdf(diag(D));
P=rand(dim);
mat=P*realDform/P;
end
function dd = comp2rdf(d)
i = find(imag(diag(d))');
index = i(1:2:length(i));
if isempty(index)
dd=d;
else
if (max(index)==size(d,1)) | any(conj(d(index,index))~=d(index+1,index+1))
error(message('Complex conjugacy not satisfied'));
end
j = sqrt(-1);
t = eye(length(d));
twobytwo = [1 1;j -j];
for i=index
t(i:i+1,i:i+1) = twobytwo;
end
dd=t*d/t;
end
end
If someone can make it a single call or shorter/more elegant code they are welcome to post an answer.

how write the following matlab code if want to fill data by for loop?

the given matlab code want to write by using "for loop"
how I can do that ?
g = {'P1','P1','P2','P2','P3','P3','P4','P4'};
I want this data by using for loop:
for f_no=1:8
g{f_no}=p(count);
count=count+1;
end
consider p has all dataset, how do I fill this as dynamic way into cell 'g'?
which will work as :
g = {'P1','P1','P2','P2','P3','P3','P4','P4'};
There are probably dozens of ways to do what you are asking. Here are 2.
%Loop
g = cell(8,1);
for p=1:4
g{p*2-1} = num2str(p,'P%d');
g{p*2} = num2str(p,'P%d');
end
%No Loop
g = cellstr(num2str(sort([1:4 1:4].'),'P%d'));
count = 1;
for f_no=1:8
g{f_no}=['P' num2str(count)];
count=count+1;
end
gives you
g = { 'P1' 'P2' 'P3' 'P4' 'P5' 'P6' 'P7' 'P8' }
OTOH,
count = 1;
for f_no=1:8
g{f_no}=['P' num2str(floor(count))];
count=count+.5;
end
gives you
g = { 'P1' 'P1' 'P2' 'P2' 'P3' 'P3' 'P4' 'P4' }
My solution:
N = [1 2 3 4];
P = repelem(N,2);
result = arrayfun(#(x)sprintf('P%d',x),P,'UniformOutput',false);
It makes use of the repelem function for duplicating each number in the vector N and of the arrayfun function for converting each number into a properly formatted string.
Alternatively, you can also use the undocumented function sprintfc and change the last line as follows:
result = sprintfc('P%d',P)
Always try to vectorize your code as much as possible when using Matlab, it performs sooooooo much better!
for f_no=1:4
g{2*f_no-1}=['P' num2str(f_no)];
g{2*f_no}=['P' num2str(f_no)];
end
It looks like 'P1' denotes p(1) cell value in which case the answer will be the same
n=size(p);
for f_no=1:n
g{2*f_no-1}=p(f_no);
g{2*f_no}=p(f_no);
end

calling a matlab function whose name contains a numeric variable

I have a set of functions such that I want to apply each of them in a separate iteration. I label the functions as: Strategy1(x), Strategy2(x)....Strategy100(x). As you can see, there is a numeric variable in the name of the function. I want to achieve something like
LS = [Strategy1(x),Strategy2(x),...,Strategy100(x)];
Y = zeros(100,1);
for i = 1:1:100
Y(i) = Strategyi(x);
end
I wonder if there is a way to achieve this goal in matlab?
You could create function handles by using str2func
n = 100;
Y = zeros(n,1);
for i = 1:n
funcH = str2func( sprintf('Strategy%d', i));
Y(i) = funcH(x);
end
If you want to concatenate the function names outside the for loop you could use srtcat
strcat('Strategy', strread( num2str(1:n), '%s'))

First input must be function handle error using arrayfun()

I'm trying to use arrayfun() to map a function over a cell array. The following is happening:
>> arrayfun(solveFunc, equArray)
Error using arrayfun
First input must be a function handle.
Error in solve>genGuess (line 33)
funcVals = abs(arrayfun(inFunc, xValues));
Error in solve (line 8)
x = genGuess(inFunc, varargin{1}, varargin{2});
Error in makeSolveFunc>#(func)solve(func,start,stop) (line 3)
sFunc = #(func) solve(func, start, stop);
But, the first input IS a function handle. Also... if I manually apply the function to each element of the provided cell array, everything works fine:
>> solveFunc(equArray{1})
ans =
4.7335
>> solveFunc(equArray{2})
ans =
4.7356
Does anyone know why this would be happening? I assumed that if I could manually apply the function to each element of my array, and the return type of the function was consistent and one of the allowed types (you can't for example have arrayfun return an array of function handles... I already tried doing that), it should work. Perhaps that is not the only requirement.
Here is some code that generates this error:
solve.m
function solution = solve(inFunc, start, stop)
%SOLVE solve an equation using Newton's Method
x = genGuess(inFunc, start, stop);
for i = 1:100
m = getSlope(inFunc, x);
x = (m*x - inFunc(x))/m;
end
solution = x;
end
function slope = getSlope(inFunc, x)
%SLOPE calculate the slope at a given point
inc = 1e-5;
if x ~= 0
inc = inc * x;
end
slope = (inFunc(x + inc) - inFunc(x - inc))/(2*inc);
end
function guess = genGuess(inFunc, start, stop)
%GENGUESS get an initial guess to the solution
xValues = linspace(start, stop, 101);
funcVals = abs(arrayfun(inFunc, xValues));
[~, minIndex] = min(funcVals);
guess = xValues(minIndex);
end
charEqu.m
function equ = charEqu(a)
%CHAREQU create a KP model characteristic equation with provided p
equ = #(x) x + a;
end
makeSolveFunc.m
function sFunc = makeSolveFunc(start, stop)
%MAKESOLVEFUNC return a function that solves an equation
sFunc = #(func) solve(func, start, stop);
end
test.m
pArray = 1:5;
equArray = cell(1,arrayLen);
for i = 1:5
equArray{i} = charEqu(pArray(i));
end
solveFunc = makeSolveFunc(1.1*pi, 2*pi);
alphaAArray = arrayfun(solveFunc, equArray);
I have narrowed down the error to something in genGuess(). For some reason, in the line funcVals = abs(arrayfun(inFunc, xValues)); the variable inFunc is a 1x1 cell array containing a function handle. I have no idea why that would be the case. I traced this back to the anonymous function call #(func) solve(func, start, stop); in the makeSolveFunc() function. There it is still a 1x1 cell array containing a function handle. I'm not really sure where that cell array is coming from as that function is getting called from arrayfun().
Background information on what I'm trying to do in case someone wants to suggest a better way:
I'm trying to solve equations using Newton's method. I have written a function that can solve an equation given an initial guess range. This function is the solve() function you can see in the first error message. It takes a function, and the guess range and returns a function that I'm calling solveFunc(). solveFunc() takes a function and solves it using the initial guess range previously provided.
Maybe I'm just too used to functional programming and should just use a loop.
If the arguments passed to the function handle are contents of elements of a cell array, you need to use cellfun instead of arrayfun:
cellfun(solveFunc, equArray)
This is equivalent to
for i=1:length(equArray)
out(i) = solveFunc(equArray{i});
end
since solveFunc is already a function handle.
Check where the error comes from. This line causes the error:
funcVals = abs(arrayfun(inFunc, xValues));
The first input argument is a 1x1 cell containing one function handle. This is caused because equArray is a cell, thus use cellfun as Jonas already mentioned:
pArray = 1:5;
equArray = cell(1,arrayLen);
for i = 1:5
equArray{i} = charEqu(pArray(i));
end
solveFunc = makeSolveFunc(1.1*pi, 2*pi);
alphaAArray = cellfun(solveFunc, equArray);

Matlab: how to work with different outputs of function

I've got the function
function [imag2] = sumIntegral(x,w,a,b,c,p)
imag2 = zeros(p-1,p);
for k = 1:p-1
f = #(t)(1:p-1==k)*Integrand[1](t,x,w,a,b,c);
imag2(k,:) = quadv(f,x(k),x(k+1));
end
whereas
Integrand[1] should be real2 of this function
[real2,real3,imag2,imag3] = Integrand(t,x,w,a,b,c,p);
The problem is, if I define the Integrand function before, I get an error, as t is undefined. Do you know how to write real2 as a function in t?
Simply define your quick function out of the for loop
function [imag2] = sumIntegral(x,w,a,b,c,p)
imag2 = zeros(p-1,p);
f = #(t)(1:p-1==k)*Integrand[1](t,x,w,a,b,c);
for k = 1:p-1
imag2(k,:) = quadv(f,x(k),x(k+1));
end
end
You could just make a dummy proxy function that only outputs the first argument:
function real2 = MyIntergrand(t,x,w,a,b,c)
real2 = Integrand(t,x,w,a,b,c);
end