Gibbs sampling gives small probabilities - machine-learning

As part of our final design project, we have to design a Gibbs sampler to denoise an image. We have chosen to use the Metropolis Algorithm instead of a regular Gibbs sampler. A rough sketch of the algorithm is as follows, all pixels are 0-255 greyscale values. Also, we are using a simple smoothness prior distribution.
main()
get input image as img
originalImg = img
for k = 1 to 1000
beta = 3/log(1+k)
initialEnergy = energy(img,originalImg)
for i = 0 to imageRows
for j = 0 to imageCols
img[i][j] = metropolisSample(beta,originalImg,img,initialEnergy,i,j)
energy(img,originalImg)
for i = 1 to imageRows
for j = 1 to imageCols
ans += (img[i][j] - originalImg[i][j])^2 / (255*255)
ans += (img[i][j] - image[i][j+1])^2 / (255*255)
ans += (img[i][j] - image[i][j-1])^2 / (255*255)
ans += (img[i][j] - image[i+1][j])^2 / (255*255)
ans += (img[i][j] - image[i-1][j])^2 / (255*255)
return ans
metropolisSample(beta,originalImg,img,initialEnergy,i,j)
imageCopy = img
imageCopy[i][j] = random int between 0 and 255
newEnergy = energy(imageCopy,originalImg)
if (newEnergy < initialEnergy)
initialEnergy = newEnergy
return imageCopy[i][j]
else
rand = random float between 0 and 1
prob = exp(-(1/beta) * (newEnergy - initialEnergy))
if rand < prob
initialEnergy = newEnergy
return imageCopy[i][j]
else
return img[i][j]
That's pretty much the gist of the program. My issue is that in the step where I calculate probability
prob = exp(-(1/beta) * (newEnergy - initialEnergy))
The difference in energies is so large that the probability is almost always zero. What is the proper way to mitigate this? We have also tried the Gibbs sampling approach, but we run into a similar problem. The Gibbs sampler code is as follows. Instead of using metropolisSample, we use gibbsSample instead
gibbsSample(beta,originalImg,img,initialEnergy,i,j)
imageCopy = img
sum = 0
for k = 0 to 255
imageCopy[i][j] = k
energies[k] = energy(imageCopy,originalImg)
prob[k] = exp(-(1/beta) * energies[k])
sum += prob[k]
for k = 0 to 255
prob[k] / sum
for k = 1 to 255
prob[k] = prob[k-1] + prob[k] //Convert our PDF to a CDF
rand = random float between 0 and 1
k = 0
while (1)
if (rand < prob[k])
break
k++
initialEnergy = energy[k]
return k
We were having similar issues with this implementation as well. When we calculated
prob[k] = exp(-(1/beta) * energies[k])
our energies were so large that our probabilities all went to zero. Theoretically, this shouldn't be an issue because we are summing them all up and then dividing by the sum, but the floating point representation just isn't accurate enough. What would be a good way to fix this?

I know nothing about your specific problem, but my first response would be to scale the energies. Your pixels are in the range of 0..255, which is arbitrary. If the pixels were fractions between zero and one, you would have very different results.
If the energy units are in pixel^2, try dividing the energies by 256^2. Else, try dividing by 256.
Also, given that the data is fully random, it is possible that there are very high energies, and there should in fact not be high probabilities.
My lack of knowledge of your problem may have resulted in a useless answer. If so, please ignore it.

I think probability for Gibbs Sampling in Ising model should be
p = 1 / (1 + np.exp(-2 * beta * Energy(x,y)))

Related

Linear Regression - Implementing Feature Scaling

I was trying to implement Linear Regression in Octave 5.1.0 on a data set relating the GRE score to the probability of Admission.
The data set is of the sort,
337 0.92
324 0.76
316 0.72
322 0.8
. . .
My main Program.m file looks like,
% read the data
data = load('Admission_Predict.txt');
% initiate variables
x = data(:,1);
y = data(:,2);
m = length(y);
theta = zeros(2,1);
alpha = 0.01;
iters = 1500;
J_hist = zeros(iters,1);
% plot data
subplot(1,2,1);
plot(x,y,'rx','MarkerSize', 10);
title('training data');
% compute cost function
x = [ones(m,1), (data(:,1) ./ 300)]; % feature scaling
J = computeCost(x,y,theta);
% run gradient descent
[theta, J_hist] = gradientDescent(x,y,theta,alpha,iters);
hold on;
subplot(1,2,1);
plot((x(:,2) .* 300), (x*theta),'-');
xlabel('GRE score');
ylabel('Probability');
hold off;
subplot (1,2,2);
plot(1:iters, J_hist, '-b');
xlabel('no: of iteration');
ylabel('Cost function');
computeCost.m looks like,
function J = computeCost(x,y,theta)
m = length(y);
h = x * theta;
J = (1/(2*m))*sum((h-y) .^ 2);
endfunction
and gradientDescent.m looks like,
function [theta, J_hist] = gradientDescent(x,y,theta,alpha,iters)
m = length(y);
J_hist = zeros(iters,1);
for i=1:iters
diff = (x*theta - y);
theta = theta - (alpha * (1/(m))) * (x' * diff);
J_hist(i) = computeCost(x,y,theta);
endfor
endfunction
The graphs plotted then looks like this,
which you can see, doesn't feel right even though my Cost function seems to be minimized.
Can someone please tell me if this is right? If not, what am I doing wrong?
The easiest way to check whether your implementation is correct is to compare with a validated implementation of linear regression. I suggest using an alternative implementation approach like the one suggested here, and then comparing your results. If the fits match, then this is the best linear fit to your data and if they don't match, then there may be something wrong in your implementation.

Generating a Histogram by Harmonic Number

I am trying to create a program in GNU Octave to draw a histogram showing the fundamental and harmonics of a modified sinewave (the output from an SCR dimmer, which consists of a sinewave which is at zero until part way through the wave).
I've been able to generate the waveform and perform FFT to get a set of Frequency vs Amplitude points, however I am not sure how to convert this data into bins suitable for generating a histogram.
Sample code and an image of what I'm after below - thanks for the help!
clear();
vrms = 120;
freq = 60;
nCycles = 2;
level = 25;
vpeak = sqrt(2) * vrms;
sampleinterval = 0.00001;
num_harmonics = 10
disp("Start");
% Draw the waveform
x = 0 : sampleinterval : nCycles * 1 / freq; % time in sampleinterval increments
dimmed_wave = [];
undimmed_wave = [];
for i = 1 : columns(x)
rad_value = x(i) * 2 * pi * freq;
off_time = mod(rad_value, pi);
on_time = pi*(100-level)/100;
if (off_time < on_time)
dimmed_wave = [dimmed_wave, 0]; % in the dimmed period, value is zero
else
dimmed_wave = [dimmed_wave, sin(rad_value)]; % when not dimmed, value = sine
endif
undimmed_wave = [undimmed_wave, sin(rad_value)];
endfor
y = dimmed_wave * vpeak; % calculate instantaneous voltage
undimmed = undimmed_wave * vpeak;
subplot(2,1,1)
plot(x*1000, y, '-', x*1000, undimmed, '--');
xlabel ("Time (ms)");
ylabel ("Voltage");
% Fourier Transform to determine harmonics
subplot(2,1,2)
N = length(dimmed_wave); % number of points
fft_vals = abs(fftshift(fft(dimmed_wave))); % perform fft
frequency = [ -(ceil((N-1)/2):-1:1) ,0 ,(1:floor((N-1)/2)) ] * 1 / (N *sampleinterval);
plot(frequency, fft_vals);
axis([0,400]);
xlabel ("Frequency");
ylabel ("Amplitude");
You know your base frequency (fundamental tone), let's call it F. 2*F is the second harmonic, 3*F the third, etc. You want to set histogram bin edges halfway between these: 1.5*F, 2.5*F, etc.
You have two periods in your input signal, therefore your (integer) base frequency is k=2 (the value at fft_vals[k+1], the first peak in your plot). The second harmonic is at k=4, the third one at k=6, etc.
So you would set your bins edges at k = 1:2:end.
In general, this would be k = nCycles/2:nCycles:end.
You can compute your bar graph according to our computed bin edges as follows:
fft_vals = abs(fft(dimmed_wave));
nHarmonics = 9;
edges = nCycles/2 + (0:nHarmonics)*nCycles;
H = cumsum(fft_vals);
H = diff(H(edges));
bar(1:nHarmonics,H);

How to get mfcc features with octave

My goal is to create program on octave that loads audio file (wav, flac), calculates its mfcc features and serve them as output. The problem is that I do not have much experience with octave and cannot get octave load the audio file and that is why I am not sure if the extraction algorithms is correct. Is there simple way of loading the file and getting its features?
You can run mfcc code from RASTAMAT in octave, you only need to fix few things, the fixed version is available for download here.
The changes are to properly set windows in powspec.m
WINDOW = hanning(winpts);
and to fix the bug in specgram function which is not compatible with Matlab.
Check out Octave functions for calculating MFCC at https://github.com/jagdish7908/mfcc-octave
For a detailed theory on steps to compute MFCC, refer http://practicalcryptography.com/miscellaneous/machine-learning/guide-mel-frequency-cepstral-coefficients-mfccs/
function frame = create_frames(y, Fs, Fsize, Fstep)
N = length(y);
% divide the signal into frames with overlap = framestep
samplesPerFrame = floor(Fs*Fsize);
samplesPerFramestep = floor(Fs*Fstep);
i = 1;
frame = [];
while(i <= N-samplesPerFrame)
frame = [frame y(i:(i+samplesPerFrame-1))];
i = i+samplesPerFramestep;
endwhile
return
endfunction
function ans = hz2mel(f)
ans = 1125*log(1+f/700);
return
endfunction
function ans = mel2hz(f)
ans = 700*(exp(f/1125) - 1);
return
endfunction
function bank = melbank(n, min, max, sr)
% n = number of banks
% min = min frequency in hertz
% max = max frequency in hertz
% convert the min and max freq in mel scale
NFFT = 512;
% figure out bin value of min and max freq
minBin = floor((NFFT)*min/(sr/2));
maxBin = floor((NFFT)*max/(sr/2));
% convert the min, max in mel scale
min_mel = hz2mel(min);
max_mel = hz2mel(max);
m = [min_mel:(max_mel-min_mel)/(n+2-1):max_mel];
%disp(m);
h = mel2hz(m);
% replace frequencies in h with thier respective bin values
fbin = floor((NFFT)*h/(sr/2));
%disp(h);
% create triangular melfilter vectors
H = zeros(NFFT,n);
for vect = 2:n+1
for k = minBin:maxBin
if k >= fbin(vect-1) && k <= fbin(vect)
H(k,vect) = (k-fbin(vect-1))/(fbin(vect)-fbin(vect-1));
elseif k >= fbin(vect) && k <= fbin(vect+1)
H(k,vect) = (fbin(vect+1) - k)/(fbin(vect+1)-fbin(vect));
endif
endfor
endfor
bank = H;
return
endfunction
clc;
clear all;
close all;
pkg load signal;
% record audio
Fs = 44100;
y = record(3,44100);
% OR %
% Load existing file
%[y, Fs] = wavread('../FILE_PATH/');
%y = y(44100:2*44100);
% create mel filterbanks
minFreq = 500; % minimum cutoff frequency in Hz
maxFreq = 10000; % maximum cutoff frequency in Hz
% melbank(number_of_banks, minFreq, mazFreq, sampling_rate)
foo = melbank(30,minFreq,maxFreq,Fs);
% create frames
frames = create_frames(y, Fs, 0.025, 0.010);
% calculate periodogram of each frame
NF = length(frames(1,:));
[P,F] = periodogram(frames(:,1),[], 1024, Fs);
% apply mel filters to the power spectra
P = foo.*P(1:512);
% sum the energy in each filter and take the logarithm
P = log(sum(P));
% take the DCT of the log filterbank energies
% discard the first coeff 'cause it'll be -Inf after taking log
L = length(P);
P = dct(P(2:L));
PXX = P;
for i = 2:NF
P = periodogram(frames(:,i),[], 1024, Fs);
% apply mel filters to the power spectra
P = foo.*P(1:512);
% sum the energy in each filter and take the logarithm
P = log(sum(P));
% take the DCT of the log filterbank energies
% discard the first coeff 'cause it'll be -Inf after taking log
P = dct(P(2:L));
% coeffients are stacked row wise for each frame
PXX = [PXX; P];
endfor
% stack the coeffients column wise
PXX = PXX';
plot(PXX);

Choosing Lines From Hough Lines

I'm using Hough Lines to do corner detection for this image. i plan to find the intersection of the lines as the corner.
This is the image.
Unfortunately, Hough return lots of lines for each line I expect
How do I tune the Hough Lines so there is only four lines each corresponds to actual line on the image?
OpenCVs hough transform really could use some better Non-Maximum Suppression. Without that, you get this phenomenon of duplicate lines. Unfortunately I know of no easy way to tune that, besides reimplementing your own hough transform. (Which is a valid option. Hough transform is fairly simple)
Fortunately it is easy to fix in post-processing:
For the non-probabilistic hough transform, OpenCv will return the lines in order of their confidence, with the strongest line first. So simply take the first four lines that differ strongly in either rho or theta.
so, add the first line found by HoughLines into a new List: strong_lines
for each line found by HoughLines:
test whether its rho and theta are close to any strong_line (e.g. rho is within 50 pixels and theta is within 10° of the other line)
if not, put it into the list of strong_lines
if you have found 4 strong_lines, break
I implemented the approach described by HugoRune and though I would share my code as an example of how I implemented this. I used a tolerance of 5 degrees and 10 pixels.
strong_lines = np.zeros([4,1,2])
minLineLength = 2
maxLineGap = 10
lines = cv2.HoughLines(edged,1,np.pi/180,10, minLineLength, maxLineGap)
n2 = 0
for n1 in range(0,len(lines)):
for rho,theta in lines[n1]:
if n1 == 0:
strong_lines[n2] = lines[n1]
n2 = n2 + 1
else:
if rho < 0:
rho*=-1
theta-=np.pi
closeness_rho = np.isclose(rho,strong_lines[0:n2,0,0],atol = 10)
closeness_theta = np.isclose(theta,strong_lines[0:n2,0,1],atol = np.pi/36)
closeness = np.all([closeness_rho,closeness_theta],axis=0)
if not any(closeness) and n2 < 4:
strong_lines[n2] = lines[n1]
n2 = n2 + 1
EDIT: The code was updated to reflect the comment regarding a negative rho value
Collect the intersection of all line
for (int i = 0; i < lines.size(); i++)
{
for (int j = i + 1; j < lines.size(); j++)
{
cv::Point2f pt = computeIntersectionOfTwoLine(lines[i], lines[j]);
if (pt.x >= 0 && pt.y >= 0 && pt.x < image.cols && pt.y < image.rows)
{
corners.push_back(pt);
}
}
}
You can google the algorithm to find the intersection of two lines.
Once you collect all the intersection points you can easily determine the min max which will give you top-left and bottom right points. From these two points you can easily get the rectangle.
Here Sorting 2d point array to find out four corners & http://opencv-code.com/tutorials/automatic-perspective-correction-for-quadrilateral-objects/ Refer these two links.
Here is a complete solution written in python 2.7.x using OpenCV 2.4.
It is based on ideas from this thread.
Method: Detect all lines. Assume that the Hough function returns highest ranked lines first. Filter the lines to keep those that are separated by some minimum distance and/or angle.
Image of all Hough lines:
https://i.ibb.co/t3JFncJ/all-lines.jpg
Filtered lines:
https://i.ibb.co/yQLNxXT/filtered-lines.jpg
Code:
http://codepad.org/J57oVIzs
"""
Detect the best 4 lines for a rounded rectangle.
"""
import numpy as np
import cv2
input_image = cv2.imread("image.jpg")
def drawLines(img, lines):
"""
Draw lines on an image
"""
for line in lines:
for rho,theta in line:
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(img, (x1,y1), (x2,y2), (0,0,255), 1)
input_image_grey = cv2.cvtColor(input_image, cv2.COLOR_BGR2GRAY)
edged = input_image_grey
rho = 1 # 1 pixel
theta = 1.0*0.017 # 1 degree
threshold = 100
lines = cv2.HoughLines(edged, rho, theta, threshold)
# Fix negative angles
num_lines = lines.shape[1]
for i in range(0, num_lines):
line = lines[0,i,:]
rho = line[0]
theta = line[1]
if rho < 0:
rho *= -1.0
theta -= np.pi
line[0] = rho
line[1] = theta
# Draw all Hough lines in red
img_with_all_lines = np.copy(input_image)
drawLines(img_with_all_lines, lines)
cv2.imshow("Hough lines", img_with_all_lines)
cv2.waitKey()
cv2.imwrite("all_lines.jpg", img_with_all_lines)
# Find 4 lines with unique rho & theta:
num_lines_to_find = 4
filtered_lines = np.zeros([1, num_lines_to_find, 2])
if lines.shape[1] < num_lines_to_find:
print("ERROR: Not enough lines detected!")
# Save the first line
filtered_lines[0,0,:] = lines[0,0,:]
print("Line 1: rho = %.1f theta = %.3f" % (filtered_lines[0,0,0], filtered_lines[0,0,1]))
idx = 1 # Index to store the next unique line
# Initialize all rows the same
for i in range(1,num_lines_to_find):
filtered_lines[0,i,:] = filtered_lines[0,0,:]
# Filter the lines
num_lines = lines.shape[1]
for i in range(0, num_lines):
line = lines[0,i,:]
rho = line[0]
theta = line[1]
# For this line, check which of the existing 4 it is similar to.
closeness_rho = np.isclose(rho, filtered_lines[0,:,0], atol = 10.0) # 10 pixels
closeness_theta = np.isclose(theta, filtered_lines[0,:,1], atol = np.pi/36.0) # 10 degrees
similar_rho = np.any(closeness_rho)
similar_theta = np.any(closeness_theta)
similar = (similar_rho and similar_theta)
if not similar:
print("Found a unique line: %d rho = %.1f theta = %.3f" % (i, rho, theta))
filtered_lines[0,idx,:] = lines[0,i,:]
idx += 1
if idx >= num_lines_to_find:
print("Found %d unique lines!" % (num_lines_to_find))
break
# Draw filtered lines
img_with_filtered_lines = np.copy(input_image)
drawLines(img_with_filtered_lines, filtered_lines)
cv2.imshow("Filtered lines", img_with_filtered_lines)
cv2.waitKey()
cv2.imwrite("filtered_lines.jpg", img_with_filtered_lines)
The above approach (proposed by #HugoRune's and implemented by #Onamission21) is correct but has a little bug. cv2.HoughLines may return negative rho and theta upto pi. Notice for example that the line (r0,0) is very close to the line (-r0,pi-epsilon) but they would not be found in the above closeness test.
I simply treated negative rhos by applying rho*=-1, theta-=pi before closeness calculations.

standard deviation of a UIImage/CGImage

I need to calculate the standard deviation on an image I have inside a UIImage object.
I know already how to access all pixels of an image, one at a time, so somehow I can do it.
I'm wondering if there is somewhere in the framework a function to perform this in a better and more efficient way... I can't find it so maybe it doensn't exist.
Do anyone know how to do this?
bye
To further expand on my comment above. I would definitely look into using the Accelerate framework, especially depending on the size of your image. If you image is a few hundred pixels by a few hundred. You will have a ton of data to process and Accelerate along with vDSP will make all of that math a lot faster since it processes everything on the GPU. I will look into this a little more, and possibly put some code in a few minutes.
UPDATE
I will post some code to do standard deviation in a single dimension using vDSP, but this could definitely be extended to 2-D
float *imageR = [0.1,0.2,0.3,0.4,...]; // vector of values
int numValues = 100; // number of values in imageR
float mean = 0; // place holder for mean
vDSP_meanv(imageR,1,&mean,numValues); // find the mean of the vector
mean = -1*mean // Invert mean so when we add it is actually subtraction
float *subMeanVec = (float*)calloc(numValues,sizeof(float)); // placeholder vector
vDSP_vsadd(imageR,1,&mean,subMeanVec,1,numValues) // subtract mean from vector
free(imageR); // free memory
float *squared = (float*)calloc(numValues,sizeof(float)); // placeholder for squared vector
vDSP_vsq(subMeanVec,1,squared,1,numValues); // Square vector element by element
free(subMeanVec); // free some memory
float sum = 0; // place holder for sum
vDSP_sve(squared,1,&sum,numValues); sum entire vector
free(squared); // free squared vector
float stdDev = sqrt(sum/numValues); // calculated std deviation
Please explain your query so that can come up with specific reply.
If I am getting you right then you want to calculate standard deviation of RGB of pixel or HSV of color, you can frame your own method of standard deviation for circular quantities in case of HSV and RGB.
We can do this by wrapping the values.
For example: Average of [358, 2] degrees is (358+2)/2=180 degrees.
But this is not correct because its average or mean should be 0 degrees.
So we wrap 358 into -2.
Now the answer is 0.
So you have to apply wrapping and then you can calculate standard deviation from above link.
UPDATE:
Convert RGB to HSV
// r,g,b values are from 0 to 1 // h = [0,360], s = [0,1], v = [0,1]
// if s == 0, then h = -1 (undefined)
void RGBtoHSV( float r, float g, float b, float *h, float *s, float *v )
{
float min, max, delta;
min = MIN( r, MIN(g, b ));
max = MAX( r, MAX(g, b ));
*v = max;
delta = max - min;
if( max != 0 )
*s = delta / max;
else {
// r = g = b = 0
*s = 0;
*h = -1;
return;
}
if( r == max )
*h = ( g - b ) / delta;
else if( g == max )
*h=2+(b-r)/delta;
else
*h=4+(r-g)/delta;
*h *= 60;
if( *h < 0 )
*h += 360;
}
and then calculate standard deviation for hue value by this:
double calcStddev(ArrayList<Double> angles){
double sin = 0;
double cos = 0;
for(int i = 0; i < angles.size(); i++){
sin += Math.sin(angles.get(i) * (Math.PI/180.0));
cos += Math.cos(angles.get(i) * (Math.PI/180.0));
}
sin /= angles.size();
cos /= angles.size();
double stddev = Math.sqrt(-Math.log(sin*sin+cos*cos));
return stddev;
}

Resources