emgu cv matrix access row and cloums with channel c# - c#

How can I access a matrix with a specified row, column and channel?
Matrix<double> tensor = new Matrix<double>(yMax + 1, xMax, 4); //4 channels
CvInvoke.cvZero(tensor);
for(int k = 0; k<x.Count; ++k)
{
double gx = Math.Cos(angle[k] * Math.PI / 180 + 90 * Math.PI / 180 + Math.PI);
double gy = Math.Sin(angle[k] * Math.PI / 180 + 90 * Math.PI / 180 + Math.PI);
tensor[y[k], x[k]] = gx * gx; //How can I access other channels?
tensor.Data[y[k], x[k] + 1] = gx * gy; //How can I access other channels?
tensor.Data[y[k], x[k] + 2] = gx * gy; //How can I access other channels?
tensor.Data[y[k], x[k] + 3] = gy * gy; //How can I access other channels?
}

I think you should give a look at Split() method and then loop on channels array.

Here is an example of getting pixel value from two separate channels of Mat:
var flowResult = new Mat();
CvInvoke.CalcOpticalFlowFarneback(_scaledDownFrameOneColorImagePrev, scaledDownFrameOneColorImage, flowResult, 0.25, 3, 15, 5, 1, 1.2, OpticalflowFarnebackFlag.Default);
var flowResultChannels = flowResult.Split();
var flowResultX = flowResultChannels[0];
var flowResultY = flowResultChannels[1];
for (var r = 0; r < flowResult.Rows; r++)
{
for (var c = 0; c < flowResult.Cols; c++)
{
var xValue = new float[1];
Marshal.Copy(flowResultX.DataPointer + (((r * flowResultX.Cols) + c) * flowResultX.ElementSize), xValue, 0, 1);
var yValue = new float[1];
Marshal.Copy(flowResultY.DataPointer + (((r * flowResultY.Cols) + c) * flowResultY.ElementSize), yValue, 0, 1);
if (Math.Abs(xValue[0]) > 3 || Math.Abs(yValue[0]) > 3)
{
Console.WriteLine("{0} {1}", xValue[0], yValue[0]);
}
}
}

Related

Convert Easting/Northing to Lat Lng

I've been struggling to convert northing/eastings to lat/long without using a nuget package. I'm sure my UTM zone is 30U (Great Britain).
How would one go about doing this in C#?
When manually done using this site. It provides the correct values and locations.
Easting: 426342 Northing: 505339
Lat/Long should be: 54.44277977022131, -1.5953328509040021
I had previously found some code on stackoverflow but it's giving me the wrong values.
utmZone = "30U"
public static LatLng ToLatLon(double utmX, double utmY, string utmZone)
{
bool isNorthHemisphere = utmZone.Last() >= 'N';
var diflat = -0.00066286966871111111111111111111111111;
var diflon = -0.0003868060578;
var zone = int.Parse(utmZone.Remove(utmZone.Length - 1));
var c_sa = 6378137.000000;
var c_sb = 6356752.314245;
var e2 = Math.Pow((Math.Pow(c_sa, 2) - Math.Pow(c_sb, 2)), 0.5) / c_sb;
var e2cuadrada = Math.Pow(e2, 2);
var c = Math.Pow(c_sa, 2) / c_sb;
var x = utmX - 500000;
var y = isNorthHemisphere ? utmY : utmY - 10000000;
var s = ((zone * 6.0) - 183.0);
var lat = y / (c_sa * 0.9996);
var v = (c / Math.Pow(1 + (e2cuadrada * Math.Pow(Math.Cos(lat), 2)), 0.5)) * 0.9996;
var a = x / v;
var a1 = Math.Sin(2 * lat);
var a2 = a1 * Math.Pow((Math.Cos(lat)), 2);
var j2 = lat + (a1 / 2.0);
var j4 = ((3 * j2) + a2) / 4.0;
var j6 = ((5 * j4) + Math.Pow(a2 * (Math.Cos(lat)), 2)) / 3.0;
var alfa = (3.0 / 4.0) * e2cuadrada;
var beta = (5.0 / 3.0) * Math.Pow(alfa, 2);
var gama = (35.0 / 27.0) * Math.Pow(alfa, 3);
var bm = 0.9996 * c * (lat - alfa * j2 + beta * j4 - gama * j6);
var b = (y - bm) / v;
var epsi = ((e2cuadrada * Math.Pow(a, 2)) / 2.0) * Math.Pow((Math.Cos(lat)), 2);
var eps = a * (1 - (epsi / 3.0));
var nab = (b * (1 - epsi)) + lat;
var senoheps = (Math.Exp(eps) - Math.Exp(-eps)) / 2.0;
var delt = Math.Atan(senoheps / (Math.Cos(nab)));
var tao = Math.Atan(Math.Cos(delt) * Math.Tan(nab));
double longitude = ((delt * (180.0 / Math.PI)) + s) + diflon;
double latitude = ((lat + (1 + e2cuadrada * Math.Pow(Math.Cos(lat), 2) - (3.0 / 2.0) * e2cuadrada * Math.Sin(lat) * Math.Cos(lat) * (tao - lat)) * (tao - lat)) * (180.0 / Math.PI)) + diflat;
return new LatLng
{
Latitude = latitude,
Longitude = longitude
};
}
Refer the below code and run LatLonConversions.ConvertOSToLatLon(426342, 505339)
public class LatLonConversions
{
const double a = 6377563.396;
const double b = 6356256.91;
const double e2 = (a - b) / a;
const double n0 = -100000;
const double e0 = 400000;
const double f0 = 0.999601272;
const double phi0 = 0.855211333;
const double lambda0 = -0.034906585;
const double n = (a - b) / (a + b);
static double lat, lng;
private LatLonConversions() { }
private static double Deg2Rad(double x)
{
return x * (Math.PI / 180);
}
private static double Rad2Deg(double x)
{
return x * (180 / Math.PI);
}
private static double SinSquared(double x)
{
return Math.Sin(x) * Math.Sin(x);
}
private static double TanSquared(double x)
{
return Math.Tan(x) * Math.Tan(x);
}
private static double Sec(double x)
{
return 1.0 / Math.Cos(x);
}
private static void OSGB36ToWGS84()
{
var airy1830 = new RefEll(6377563.396, 6356256.909);
var a = airy1830.maj;
var b = airy1830.min;
var eSquared = airy1830.ecc;
var phi = Deg2Rad(lat);
var lambda = Deg2Rad(lng);
var v = a / (Math.Sqrt(1 - eSquared * SinSquared(phi)));
var H = 0; // height
var x = (v + H) * Math.Cos(phi) * Math.Cos(lambda);
var y = (v + H) * Math.Cos(phi) * Math.Sin(lambda);
var z = ((1 - eSquared) * v + H) * Math.Sin(phi);
var tx = 446.448;
var ty = -124.157;
var tz = 542.060;
var s = -0.0000204894;
var rx = Deg2Rad(0.00004172222);
var ry = Deg2Rad(0.00006861111);
var rz = Deg2Rad(0.00023391666);
var xB = tx + (x * (1 + s)) + (-rx * y) + (ry * z);
var yB = ty + (rz * x) + (y * (1 + s)) + (-rx * z);
var zB = tz + (-ry * x) + (rx * y) + (z * (1 + s));
var wgs84 = new RefEll(6378137.000, 6356752.3141);
a = wgs84.maj;
b = wgs84.min;
eSquared = wgs84.ecc;
var lambdaB = Rad2Deg(Math.Atan(yB / xB));
var p = Math.Sqrt((xB * xB) + (yB * yB));
var phiN = Math.Atan(zB / (p * (1 - eSquared)));
for (var i = 1; i < 10; i++)
{
v = a / (Math.Sqrt(1 - eSquared * SinSquared(phiN)));
double phiN1 = Math.Atan((zB + (eSquared * v * Math.Sin(phiN))) / p);
phiN = phiN1;
}
var phiB = Rad2Deg(phiN);
lat = phiB;
lng = lambdaB;
}
public static LatLon ConvertOSToLatLon(double easting, double northing)
{
RefEll airy1830 = new RefEll(6377563.396, 6356256.909);
double OSGB_F0 = 0.9996012717;
double N0 = -100000.0;
double E0 = 400000.0;
double phi0 = Deg2Rad(49.0);
double lambda0 = Deg2Rad(-2.0);
double a = airy1830.maj;
double b = airy1830.min;
double eSquared = airy1830.ecc;
double phi = 0.0;
double lambda = 0.0;
double E = easting;
double N = northing;
double n = (a - b) / (a + b);
double M = 0.0;
double phiPrime = ((N - N0) / (a * OSGB_F0)) + phi0;
do
{
M =
(b * OSGB_F0)
* (((1 + n + ((5.0 / 4.0) * n * n) + ((5.0 / 4.0) * n * n * n))
* (phiPrime - phi0))
- (((3 * n) + (3 * n * n) + ((21.0 / 8.0) * n * n * n))
* Math.Sin(phiPrime - phi0)
* Math.Cos(phiPrime + phi0))
+ ((((15.0 / 8.0) * n * n) + ((15.0 / 8.0) * n * n * n))
* Math.Sin(2.0 * (phiPrime - phi0))
* Math.Cos(2.0 * (phiPrime + phi0)))
- (((35.0 / 24.0) * n * n * n)
* Math.Sin(3.0 * (phiPrime - phi0))
* Math.Cos(3.0 * (phiPrime + phi0))));
phiPrime += (N - N0 - M) / (a * OSGB_F0);
} while ((N - N0 - M) >= 0.001);
var v = a * OSGB_F0 * Math.Pow(1.0 - eSquared * SinSquared(phiPrime), -0.5);
var rho =
a
* OSGB_F0
* (1.0 - eSquared)
* Math.Pow(1.0 - eSquared * SinSquared(phiPrime), -1.5);
var etaSquared = (v / rho) - 1.0;
var VII = Math.Tan(phiPrime) / (2 * rho * v);
var VIII =
(Math.Tan(phiPrime) / (24.0 * rho * Math.Pow(v, 3.0)))
* (5.0
+ (3.0 * TanSquared(phiPrime))
+ etaSquared
- (9.0 * TanSquared(phiPrime) * etaSquared));
var IX =
(Math.Tan(phiPrime) / (720.0 * rho * Math.Pow(v, 5.0)))
* (61.0
+ (90.0 * TanSquared(phiPrime))
+ (45.0 * TanSquared(phiPrime) * TanSquared(phiPrime)));
var X = Sec(phiPrime) / v;
var XI =
(Sec(phiPrime) / (6.0 * v * v * v))
* ((v / rho) + (2 * TanSquared(phiPrime)));
var XII =
(Sec(phiPrime) / (120.0 * Math.Pow(v, 5.0)))
* (5.0
+ (28.0 * TanSquared(phiPrime))
+ (24.0 * TanSquared(phiPrime) * TanSquared(phiPrime)));
var XIIA =
(Sec(phiPrime) / (5040.0 * Math.Pow(v, 7.0)))
* (61.0
+ (662.0 * TanSquared(phiPrime))
+ (1320.0 * TanSquared(phiPrime) * TanSquared(phiPrime))
+ (720.0
* TanSquared(phiPrime)
* TanSquared(phiPrime)
* TanSquared(phiPrime)));
phi =
phiPrime
- (VII * Math.Pow(E - E0, 2.0))
+ (VIII * Math.Pow(E - E0, 4.0))
- (IX * Math.Pow(E - E0, 6.0));
lambda =
lambda0
+ (X * (E - E0))
- (XI * Math.Pow(E - E0, 3.0))
+ (XII * Math.Pow(E - E0, 5.0))
- (XIIA * Math.Pow(E - E0, 7.0));
lat = Rad2Deg(phi);
lng = Rad2Deg(lambda);
// convert to WGS84
OSGB36ToWGS84();
return new LatLon(lat, lng);
}
}
public class RefEll
{
public double maj, min, ecc;
public RefEll(double major, double minor)
{
maj = major;
min = minor;
ecc = ((major * major) - (minor * minor)) / (major * major);
}
}
public class LatLon
{
public double Latitude;
public double Longitude;
public LatLon()
{
Latitude = 0;
Longitude = 0;
}
public LatLon(double lat, double lon)
{
Latitude = lat;
Longitude = lon;
}
}
I ran into the same issue. Ended up using this library: https://github.com/Tronald/CoordinateSharp
This sample will return the exact position in latlon decimal.
UniversalTransverseMercator utm = new UniversalTransverseMercator("T", 30, 581177.3879, 4794824.5279);
Coordinate c = UniversalTransverseMercator.ConvertUTMtoLatLong(utm);
c.FormatOptions.Format = CoordinateFormatType.Decimal;
c.FormatOptions.Round = 7;
Debug.Log($"({c.Latitude}, {c.Longitude})");

Why is converting RGB to CMYK not showing the correct result

I am using this site as a reference: http://www.rapidtables.com/convert/color/rgb-to-cmyk.htm
My code:
public void Convert2CMYK()
{
float c, m, y, k;
if (inRed == 0 && inGreen == 0 && inBlue == 0)
{
tbCyan.Text = "0";
tbMagenta.Text = "0";
tbYellow.Text = "0";
tbBlack.Text = "1";
}
c = 1 - (inRed / 255f);
m = 1 - (inGreen / 255f);
y = 1 - (inBlue / 255f);
var minCMY = Math.Min(c, Math.Min(m, y));
c = (c - minCMY) / (1 - minCMY) * 100;
m = (m - minCMY) / (1 - minCMY) * 100;
y = (y - minCMY) / (1 - minCMY) * 100;
k = minCMY * 100;
tbCyan.Text = c.ToString();
tbMagenta.Text = m.ToString();
tbYellow.Text = y.ToString();
tbBlack.Text = k.ToString();
}
On the site, R=25, G=25, B=25 results in C=0, M=0, Y=0, K=0.902
In the app (my code), R=25, G=25, B=25 results in C=0, M=0, Y=0, K=90.19608
What do I have to modify to ensure my results are accurate.
Thanks to everyone for their help. Here are the final equations which did the trick:
c = Math.Round((c - minCMY) / (1 - minCMY), 3);
m = Math.Round((m - minCMY) / (1 - minCMY), 3);
y = Math.Round((y - minCMY) / (1 - minCMY), 3);
k = Math.Round(minCMY, 3);

Correctly implementing Dolby Pro Logic II

So far I've managed to implement Dolby's Matrix Decoder based on the following specifications:
Left Right
Center 0.707 0.707
Left 1 0
Right 0 1
SLeft 0.871 0.489
SRight 0.489 0.871
But after testing my matrix I've discovered there's a lot clipping, and it sounds nothing like Dolby's decoder. I'm relatively new to DSP, although I'm pretty sure I understand most of the basics; but I'm still left clueless as to what's causing this to happen, am I missing something in the specifications, or is it just my code?
My current matrix decoder,
private static void DolbyProLogicII(List<float> leftSamples, List<float> rightSamples, int sampleRate, string outputDirectory)
{
// WavFileWrite is a wrapper class for NAudio to create Wav files.
var meta = new WaveFormat(sampleRate, 16, 1);
var c = new WavFileWrite { MetaData = meta, FileName = Path.Combine(outputDirectory, "c.wav") };
var l = new WavFileWrite { MetaData = meta, FileName = Path.Combine(outputDirectory, "l.wav") };
var r = new WavFileWrite { MetaData = meta, FileName = Path.Combine(outputDirectory, "r.wav") };
var sl = new WavFileWrite { MetaData = meta, FileName = Path.Combine(outputDirectory, "sl.wav") };
var sr = new WavFileWrite { MetaData = meta, FileName = Path.Combine(outputDirectory, "sr.wav") };
var ii = (leftSamples.Count > rightSamples.Count ? rightSamples.Count : leftSamples.Count);
// Process center channel.
for (var i = 0; i < ii; i++)
{
c.MonoChannelAudioData.Add((leftSamples[i] * 0.707) + (rightSamples[i] * 0.707));
}
c.Flush();
// Process left channel.
l.MonoChannelAudioData = leftSamples;
l.Flush();
// Process right channel.
r.MonoChannelAudioData = rightSamples;
r.Flush();
// Process surround left channel.
for (var i = 0; i < ii - 1; i++)
{
sl.MonoChannelAudioData.Add((leftSamples[i] * 0.871) + (rightSamples[i] * 0.489));
}
sl.Flush();
// Process surround right channel.
for (var i = 0; i < ii - 1; i++)
{
sr.MonoChannelAudioData.Add((leftSamples[i] * 0.489) + (rightSamples[i] * 0.871));
}
sr.Flush();
}
Tl;dr
To strictly compare your implementation with Dolby's specifications, you're missing several things,
The decoder's mixing levels (not the ratios) are incorrect,
The LFE channel isn't being processed,
The surround left & surround right channels aren't phase shifted, delayed, or passed through a HPF,
And the center channel isn't passed through a Bandpass.
The right mix
The clipping problem is the result of your maxtrix mixing levels (the ratios are fine), for example, the center channel is being over amp'd by 41.4% since 0.707 + 0.707 = 1.414; so, to retain the correct ratios simply halve your mixing levels.
With that in mind, your maxtrix should now look like this,
Left Right
Center 0.354 0.354
Left 0.5 0
Right 0 0.5
SLeft 0.436 0.245
SRight 0.245 0.436
Adding the LFE
If you're not intentionally leaving out the LFE channel, you can decode it just like the center channel, but you must apply an LPF at 120Hz (Dolby's standard).
Making the surround channels actually "surround"
To process the surround left and surround right channels, you'll need to pass the left and right channels through a HPF at 100 Hz then apply a 90o phase shift (then invert the left side); mix, and then add a delay (I believe Dolby doesn't specify the exact amount of time, but after some testing I've found the "sweetspot" appears to be around 10 milliseconds).
(If you're going to play around with the delay, I'd recommend doing so between 5ms to 12.5ms (feel free to experiment). If the delay is too small you'll end up with a "compressed/condensed" sounding mix, too long, and you'll end up with an awful echoing of higher frequencies in the background. Ideally, the end result should sound as "airy/open" as possible, but without any hint of echoing/reverberation.)
leftSamples -> HPF -> phase shift -> invert -> mix \
-> delay
rightSamples -> HPF -> phase shift -> mix /
The Center channel
Dolby also specifies that the center channel needs to be passed through a bandpass at 70Hz to 20kHz (after mixing).
Finally...
So, putting that all together you should end up with the following,
public void DolbyProLogicII(float[] leftSamples, float[] rightSamples, int sampleRate)
{
var ii = Math.Min(leftSamples.Length, rightSamples.Length);
var c = new float[ii];
var l = new float[ii];
var r = new float[ii];
var sl = new float[ii];
var sr = new float[ii];
var lfe = new float[ii];
// Process center channel
for (var i = 0; i < ii; i++)
{
// Best to be as precise as possible.
c[i] = (leftSamples[i] * 0.35355339059327376220042218105242f) + (rightSamples[i] * 0.35355339059327376220042218105242f);
}
c = LinkwitzRileyHighPass(c, sampleRate, 70);
c = LinkwitzRileyLowPass(c, sampleRate, 20000);
// Process front left channel
for (var i = 0; i < ii; i++)
{
l[i] = leftSamples[i] * 0.5f;
}
// Process front right channel
for (var i = 0; i < ii; i++)
{
r[i] = rightSamples[i] * 0.5f;
}
// Process left samples for SL channel
var slL = new float[ii];
for (var i = 0; i < ii; i++)
{
slL[ii] = leftSamples[i] * 0.43588989435406735522369819838596f;
}
slL = LinkwitzRileyHighPass(slL, sampleRate, 100);
slL = PhaseShift(slL, sampleRate, true);
// Process right samples for SL channel.
var slR = new float[ii];
for (var i = 0; i < ii; i++)
{
slR[i] = rightSamples[i] * 0.24494897427831780981972840747059f;
}
slR = LinkwitzRileyHighPass(slR, sampleRate, 100);
slR = PhaseShift(slR, sampleRate);
// Combine new left & right samples for SL channel
for (var i = 0; i < ii - 1; i++)
{
sl[i] = slL[i] + slR[i];
}
sl = Delay(sl, sampleRate, 10);
// Process left samples for SR channel
var srL = new float[ii];
for (var i = 0; i < ii; i++)
{
srL[i] = leftSamples[i] * 0.24494897427831780981972840747059f;
}
srL = LinkwitzRileyHighPass(srL, sampleRate, 100);
srL = PhaseShift(srL, sampleRate, true);
// Process right samples for SR channel
var srR = new float[ii];
for (var i = 0; i < ii; i++)
{
srR[i] = rightSamples[i] * 0.43588989435406735522369819838596f;
}
srR = LinkwitzRileyHighPass(srR, sampleRate, 100);
srR = PhaseShift(srR, sampleRate);
// Combine new left & right samples for SR channel
for (var i = 0; i < ii - 1; i++)
{
sr[i] = srL[i] + srR[i];
}
sr = Delay(sr, sampleRate, 10);
// Process LFE channel.
for (var i = 0; i < ii; i++)
{
lfe[i] = (leftSamples[i] * 0.35355339059327376220042218105242f) + (rightSamples[i] * 0.35355339059327376220042218105242f);
}
lfe = LinkwitzRileyLowPass(lfe, sampleRate, 120);
}
public float[] PhaseShift(float[] samples, double sampleRate, bool invertOutput = false)
{
var depth = 4.0;
var delay = 100.0;
var rate = 0.1;
var newSamples = new float[samples.Length];
double wp, min_wp, max_wp, range, coef, sweepfac;
double inval, x1, outval = 0.0;
double lx1 = 0.0, ly1 = 0.0, lx2 = 0.0, ly2 = 0.0, lx3 = 0.0, ly3 = 0.0, lx4 = 0.0, ly4 = 0.0;
// calc params for sweeping filters
wp = min_wp = (Math.PI * delay) / sampleRate;
range = Math.Pow(2.0, depth);
max_wp = (Math.PI * delay * range) / sampleRate;
rate = Math.Pow(range, rate / (sampleRate / 2));
sweepfac = rate;
for (var i = 0; i < samples.Length; i++)
{
coef = (1.0 - wp) / (1.0 + wp); // calc coef for current freq
x1 = (inval = (double)samples[i]);
ly1 = coef * (ly1 + x1) - lx1; // do 1st filter
lx1 = x1;
ly2 = coef * (ly2 + ly1) - lx2; // do 2nd filter
lx2 = ly1;
ly3 = coef * (ly3 + ly2) - lx3; // do 3rd filter
lx3 = ly2;
ly4 = coef * (ly4 + ly3) - lx4; // do 4th filter
lx4 = ly3;
// final output
outval = ly4;
if (invertOutput)
{
newSamples[i] = -(float)outval;
}
else
{
newSamples[i] = (float)outval;
}
wp *= sweepfac; // adjust freq of filters
if (wp > max_wp) // max?
{
sweepfac = 1.0 / rate; // sweep back down
}
else
{
if (wp < min_wp) // min?
{
sweepfac = rate; // sweep back up
}
}
}
return newSamples;
}
public float[] Delay(float[] samples, int sampleRate, double milliseconds)
{
var output = new List<float>(samples);
var ii = (sampleRate / 1000) * milliseconds;
for (var i = 0; i < ii; i++)
{
output.Insert(0, 0);
}
return output.ToArray();
}
public float[] LinkwitzRileyHighPass(float[] samples, int sampleRate, double cutoff)
{
if (cutoff <= 0 && cutoff >= sampleRate / 2)
{
throw new ArgumentOutOfRangeException("cutoff", "The cutoff frequency must be between 0 and \"sampleRate\" / 2.");
}
if (sampleRate <= 0)
{
throw new ArgumentOutOfRangeException("sampleRate", "The sample rate must be more than 0.");
}
if (samples == null || samples.Length == 0)
{
throw new ArgumentNullException("samples", "\"samples\" can not be null or empty.");
}
var newSamples = new float[samples.Length];
var wc = 2 * Math.PI * cutoff;
var wc2 = wc * wc;
var wc3 = wc2 * wc;
var wc4 = wc2 * wc2;
var k = wc / Math.Tan(Math.PI * cutoff / sampleRate);
var k2 = k * k;
var k3 = k2 * k;
var k4 = k2 * k2;
var sqrt2 = Math.Sqrt(2);
var sq_tmp1 = sqrt2 * wc3 * k;
var sq_tmp2 = sqrt2 * wc * k3;
var a_tmp = 4 * wc2 * k2 + 2 * sq_tmp1 + k4 + 2 * sq_tmp2 + wc4;
var b1 = (4 * (wc4 + sq_tmp1 - k4 - sq_tmp2)) / a_tmp;
var b2 = (6 * wc4 - 8 * wc2 * k2 + 6 * k4) / a_tmp;
var b3 = (4 * (wc4 - sq_tmp1 + sq_tmp2 - k4)) / a_tmp;
var b4 = (k4 - 2 * sq_tmp1 + wc4 - 2 * sq_tmp2 + 4 * wc2 * k2) / a_tmp;
var a0 = k4 / a_tmp;
var a1 = -4 * k4 / a_tmp;
var a2 = 6 * k4 / a_tmp;
var a3 = a1;
var a4 = a0;
double ym1 = 0.0, ym2 = 0.0, ym3 = 0.0, ym4 = 0.0, xm1 = 0.0, xm2 = 0.0, xm3 = 0.0, xm4 = 0.0, tempy = 0.0;
for (var i = 0; i < samples.Length; i++)
{
var tempx = samples[i];
tempy = a0 * tempx + a1 * xm1 + a2 * xm2 + a3 * xm3 + a4 * xm4 - b1 * ym1 - b2 * ym2 - b3 * ym3 - b4 * ym4;
xm4 = xm3;
xm3 = xm2;
xm2 = xm1;
xm1 = tempx;
ym4 = ym3;
ym3 = ym2;
ym2 = ym1;
ym1 = tempy;
newSamples[i] = (float)tempy;
}
return newSamples;
}
public float[] LinkwitzRileyLowPass(float[] samples, int sampleRate, double cutoff)
{
if (cutoff <= 0 && cutoff >= sampleRate / 2)
{
throw new ArgumentOutOfRangeException("cutoff", "The cutoff frequency must be between 0 and \"sampleRate\" / 2.");
}
if (sampleRate <= 0)
{
throw new ArgumentOutOfRangeException("sampleRate", "The sample rate must be more than 0.");
}
if (samples == null || samples.Length == 0)
{
throw new ArgumentNullException("samples", "\"samples\" can not be null or empty.");
}
var newSamples = new float[samples.Length];
var wc = 2 * Math.PI * cutoff;
var wc2 = wc * wc;
var wc3 = wc2 * wc;
var wc4 = wc2 * wc2;
var k = wc / Math.Tan(Math.PI * cutoff / sampleRate);
var k2 = k * k;
var k3 = k2 * k;
var k4 = k2 * k2;
var sqrt2 = Math.Sqrt(2);
var sq_tmp1 = sqrt2 * wc3 * k;
var sq_tmp2 = sqrt2 * wc * k3;
var a_tmp = 4 * wc2 * k2 + 2 * sq_tmp1 + k4 + 2 * sq_tmp2 + wc4;
var b1 = (4 * (wc4 + sq_tmp1 - k4 - sq_tmp2)) / a_tmp;
var b2 = (6 * wc4 - 8 * wc2 * k2 + 6 * k4) / a_tmp;
var b3 = (4 * (wc4 - sq_tmp1 + sq_tmp2 - k4)) / a_tmp;
var b4 = (k4 - 2 * sq_tmp1 + wc4 - 2 * sq_tmp2 + 4 * wc2 * k2) / a_tmp;
var a0 = wc4 / a_tmp;
var a1 = 4 * wc4 / a_tmp;
var a2 = 6 * wc4 / a_tmp;
var a3 = a1;
var a4 = a0;
double ym1 = 0.0, ym2 = 0.0, ym3 = 0.0, ym4 = 0.0, xm1 = 0.0, xm2 = 0.0, xm3 = 0.0, xm4 = 0.0, tempy = 0.0;
for (var i = 0; i < samples.Length; i++)
{
var tempx = samples[i];
tempy = a0 * tempx + a1 * xm1 + a2 * xm2 + a3 * xm3 + a4 * xm4 - b1 * ym1 - b2 * ym2 - b3 * ym3 - b4 * ym4;
xm4 = xm3;
xm3 = xm2;
xm2 = xm1;
xm1 = tempx;
ym4 = ym3;
ym3 = ym2;
ym2 = ym1;
ym1 = tempy;
newSamples[i] = (float)tempy;
}
return newSamples;
}

C# solving system of quadratic equations

How do you solve this type of equation?
a *X + b * Y + c *Z = q
d *X + e * Y + f *Z = w
X *X + Y * Y + Z *Z = z
We are looking for X,Y,Z. If not the squares in the last row this could be solved as a typical linear equation, for example using Linear Equations from Dot Numerics, or writing Gauss Elimination.
But how do I solve this one? Also, do you know any libraries in .NET that solves that equation?
This may be viewed as a set of equations for 2 planes and a sphere. The solution finds the intersection of the 2 planes (a line) and then the intersection of that line with the sphere.
There may be 0, 1, or 2 unique solutions.
The code is C, but I assume OP can readily translate to c#
// Eq1: a *X + b * Y + c *Z = q
// Eq2: d *X + e * Y + f *Z = w
// Eq3: X *X + Y * Y + Z *Z = z
typedef struct {
double x,y,z,s;
} plane_t;
typedef struct {
double x,y,z;
} point_t;
int Interection_PlanePlaneSphere(point_t XYZ[2], const plane_t *abc, const plane_t *def, double radius) {
// Find intersection of 2 planes
// V = abc cross def
point_t V; // This is really 3D vector, not a point
V.x = abc->y*def->z - abc->z*def->y;
V.y = abc->z*def->x - abc->x*def->z;
V.z = abc->x*def->y - abc->y*def->x;
// printf("V (%12g, %12g, %12g)\n", V.x, V.y, V.z);
// Assume both planes go through z plane, e.g. z = 0 and V.z != 0
// Code could be adapted to not depend on this assumption.
// abc->x*P.x + abc->y*P.y = abc->s
// def->x*P.x + def->y*P.y = def->s
double det = abc->x*def->y - abc->y*def->x;
// if Planes are parallel ...
// Code could be adapted to deal with special case where planes are coincident.
if (det == 0.0) return 0; //
point_t P;
P.x = ( abc->s*def->y - def->s*abc->y)/det;
P.y = (-abc->s*def->x + def->s*abc->x)/det;
P.z = 0.0;
// L(t) = P + V*t = intersection of the 2 planes
// printf("p (%12g, %12g, %12g)\n", P.x, P.y, P.z);
if (radius < 0) return 0; // bad sphere
// Find where L(t) is on the sphere, or |L(t)| = radius^2
// (P.x - V.x*t)^2 + (P.y - V.y*t)^2 + (P.z - V.z*t)^2 = radius^2
// (V.x^2 + V.y^2 + V.z^2)*t^2 - 2*(P.x*V.x + P.y*V.y + P.z*V.z) + (P.x^2 + P.y^2 + P.z^2) = radius^2;
// Solve quadratic
double a, b, c;
a = V.x*V.x + V.y*V.y + V.z*V.z;
b = -2*(P.x*V.x + P.y*V.y + P.z*V.z);
c = P.x*P.x + P.y*P.y + P.z*P.z - radius*radius;
// printf("abc (%12g, %12g, %12g)\n", a, b, c);
det = b*b - 4*a*c;
if (det < 0) return 0; // no solutions
det = sqrt(det);
double t;
t = (-b + det)/(2*a);
XYZ[0].x = P.x + t*V.x;
XYZ[0].y = P.y + t*V.y;
XYZ[0].z = P.z + t*V.z;
if (det == 0.0) return 1;
t = (-b - det)/(2*a);
XYZ[1].x = P.x + t*V.x;
XYZ[1].y = P.y + t*V.y;
XYZ[1].z = P.z + t*V.z;
return 2;
}
void Test() {
plane_t abcq = {2, -1, 1, 5};
plane_t defw = {1, 1, -1, 1};
double z = 100;
point_t XYZ[2];
int result = Interection_PlanePlaneSphere(XYZ, &abcq, &defw, sqrt(z));
printf("Result %d\n", result);
int i=0;
for (i=0; i<result; i++) {
printf("XYZ[%d] (%12g, %12g, %12g)\n", i, XYZ[i].x, XYZ[i].y, XYZ[i].z);
}
// Result 2
// XYZ[0] ( 2, 5.41014, 6.41014)
// XYZ[1] ( 2, -8.41014, -7.41014)
}

Midpoint displacement algorithm - weird results

I am writing my own midpoint displacement algorithm for learning purposes and I decided to implement it in my own way to see if I was 1) able to understand the algorithm and 2) see if i could modify it to my liking.
here is the code to generate the fractal:
public void Generate(Double rg, int size)
{
Random rand = new Random();
int min = -127;
int max = 128;
// Starting points of the rectangle
MDP_Point s1 = new MDP_Point(0, 0, rand.Next(min, max));
MDP_Point s2 = new MDP_Point(size, 0, rand.Next(min, max));
MDP_Point s3 = new MDP_Point(size, size, rand.Next(min, max));
MDP_Point s4 = new MDP_Point(0, size, rand.Next(min, max));
// Lists containing the rectangles
List<MDP_Rect> newRect = new List<MDP_Rect>(); // Newly created rectangles
List<MDP_Rect> oldRect = new List<MDP_Rect>(); // Rectangles being divided
// Starting rectangle is added to the list
oldRect.Add(new MDP_Rect(s1, s2, s3, s4));
// Distance between 2 points in a rectangle
int h = size;
while (h > 1)
{
foreach (MDP_Rect r in oldRect)
{
// Middle points of rectangle segments
MDP_Point m1 = new MDP_Point();
MDP_Point m2 = new MDP_Point();
MDP_Point m3 = new MDP_Point();
MDP_Point m4 = new MDP_Point();
// Middle point of rectangle
MDP_Point mm = new MDP_Point();
m1.x = (r.C1.x + r.C2.x) / 2;
m1.y = (r.C1.y + r.C2.y) / 2;
m1.z = ((r.C1.z + r.C2.z) / 2) +(rand.Next(min, max) * rg);
m2.x = (r.C2.x + r.C3.x) / 2;
m2.y = (r.C2.y + r.C3.y) / 2;
m2.z = ((r.C2.z + r.C3.z) / 2) +(rand.Next(min, max) * rg);
m3.x = (r.C3.x + r.C4.x) / 2;
m3.y = (r.C3.y + r.C4.y) / 2;
m3.z = ((r.C3.z + r.C4.z) / 2) +(rand.Next(min, max) * rg);
m4.x = (r.C1.x + r.C4.x) / 2;
m4.y = (r.C1.y + r.C4.y) / 2;
m4.z = ((r.C1.z + r.C4.z) / 2) + (rand.Next(min, max) * rg);
mm.x = (r.C1.x + r.C2.x + r.C3.x + r.C4.x) / 4;
mm.y = (r.C1.y + r.C2.y + r.C3.y + r.C4.y) / 4;
mm.z = ((r.C1.z + r.C2.z + r.C3.z + r.C4.z) / 4) + (rand.Next(min, max) * rg);
newRect.Add(new MDP_Rect(r.C1, m1, mm, m4));
newRect.Add(new MDP_Rect(m1, r.C2, m2, mm));
newRect.Add(new MDP_Rect(mm, m2, r.C3, m3));
newRect.Add(new MDP_Rect(m4, mm, m3, r.C4));
}
oldRect.Clear();
oldRect = new List<MDP_Rect>(newRect);
newRect.Clear();
h /= 2;
}
List<MDP_Rect> sorted = new List<MDP_Rect>();
sorted = oldRect.OrderBy(y => y.C1.y).ThenBy(x => x.C1.x).ToList();
List<MDP_Point> mapArray = new List<MDP_Point>();
mapArray.AddRange(CreateArray(sorted));
CreateImage(size, mapArray, rg);
}
MDP_Point only contains x, y and z values
MDP_Rectangle contains 4 points, creating a rectangle
The CreateArray() method only takes the ordered rectangle list and outputs and list of points in the correct order to create an image.
CreateArray():
private List<MDP_Point> CreateArray(List<MDP_Rect> lRect)
{
List<MDP_Point> p = new List<MDP_Point>();
int size = (int)Math.Sqrt(lRect.Count);
int i = 0;
foreach (MDP_Rect r in lRect)
{
p.Add(new MDP_Point((int)r.C1.x, (int)r.C1.y, (int)r.C1.z));
if (i > 0 && i % size == size - 1)
{
p.Add(new MDP_Point((int)r.C2.x, (int)r.C2.y, (int)r.C2.z));
}
i++;
}
for (int a = 0; a < size; a++)
{
p.Add(new MDP_Point((int)lRect[(size * size - size) + a].C4.x,
(int)lRect[(size * size - size) + a].C4.y,
(int)lRect[(size * size - size) + a].C4.z));
if (a > 0 && a % size == size - 1)
{
p.Add(new MDP_Point((int)lRect[(size * size - size) + a].C3.x,
(int)lRect[(size * size - size) + a].C3.y,
(int)lRect[(size * size - size) + a].C3.z));
}
}
return p;
}
This is the method to create the image:
private void CreateImage(int size, List<MDP_Point> arr, double roughness)
{
Bitmap map = new Bitmap(size, size);
int ver = 0;
for (int i = 0; i < map.Height; i++)
{
for (int n = 0; n < map.Width; n++ )
{
int h = (int)arr[ver].z + 127;
if (h < 0)
{
h = 0;
}
else if (h > 255)
{
h = 255 ;
}
Color c = Color.FromArgb(h, h, h);
//map.SetPixel(n, i, c);
map.SetPixel(i, n, c);
ver++;
}
}
Bitmap m = new Bitmap(map);
bool saved = true;
int num = 0;
while (saved)
{
if (File.Exists("map_S" + size + "_R" + roughness + "_" + num + ".png"))
{
num++;
}
else
{
m.Save("map_S" + size + "_R" + roughness + "_" + num + ".png", System.Drawing.Imaging.ImageFormat.Png);
saved = false;
}
}
map.Dispose();
m.Dispose();
}
The fact that any value below 0 is set to 0 and any value above 255 is set to 255 is probably a big issue.... not sure what to do about it.
Here's an image generated by the code:
Size: 1024
Roughness: 0.5
The most obvious issues are the diagonal "ridge lines" and the tiled look there is.
At this point, i'm not sure what to do to fix this to make it look more natural.
Any ideas?
Here, I think part of the problem is your hacking of the h variable with 255 and 0. I tried the code using:
int h = (int) arr[ver].z;
if (h < 0)
{
h = Math.Abs(h);
}
while(h > 255)
{
h -= 255;
}
On my PC the result was:
and when I used:
int h = (int) arr[ver].z + 127;
Note that I just had to create a testing MDP_Point class and MDP_Rect to test this...
To avoid these artifacts, you should use the two-stage method proposed by Peitgen et al. in "The Science of Fractal Images". They also suggest adding additional random displacements to all vertices after each subdivision step. I found a scanned excerpt here (page 45):
http://cs455.cs.byu.edu/lectureslides/FractalsPart2.pdf

Categories

Resources