The two-step filtering is because the Gaussian is separable: the code convolves with two 1D filters, once along each of the axes (note the transpose operation!). This is the right way to do it. The function CONV2 actually supports separable filters, you can substitute this code:
Ix = conv2(conv2(I,-gp,'same'),g','same');
with:
Ix = conv2(g,-gp,I,'same');
These produce the same result and I guess there is not much difference in execution time either. It only makes the code simpler to read.
Not only the definition of the derivative of the Gaussian is wrong, the Gaussian itself is also wrong: it needs to be normalized!
g = exp(-(x.^2)/(2*sigma^2)) / (sigma*sqrt(2*pi));
gp = -(x/sigma^2) .* g;
Also, the filter support is a little small, especially for the derivative. I would use ceil(3*sigma).
My last comment:
I think that what Urs meant was that, when you compute the filter under a number of orientations, you perform the same convolutions over and over again. Calculating the kernel is not that much work at all, calculating the two convolutions is quite a bit more work! You can reuse the images Ix and Iy to compute the filter result under any orientation, this is the interesting part of the steerable filter. Your function should store Ix and Iy in the output argument h, not the Gaussian kernels g and gp.
I have also noticed the error in the first derivative of the Gaussian at line 108.
For your second question, I think that a Gaussian smoothing helps as a preprocessing step to remove noise.
line 108: gp = -(x/sigma).*exp(-(x.^2)/(2*sigma^2));
The derivative is not taken correctly, it should be:
gp = -(x/sigma^2).*exp(-(x.^2)/(2*sigma^2));
Another question is why do you convolve the image with gaussian itself? Looks like you doing two step filtering, convolving with gaussian and then with its derivative.
Comment only