Hello guys i am trying plotting the mandlebrot fractal but the result is very far from it, can you help me to find the why?
Here is the code:
void Button1Click(object sender, EventArgs e)
{
Graphics g = pbx.CreateGraphics();
Pen p = new Pen(Color.Black);
double xmin = -2.0;
double ymin = -1.2;
double xmax = 0;
double ymax = 0;
double x = xmin, y = ymin;
int MAX = 1000;
double stepY = Math.Abs(ymin - ymax)/(pbx.Height);
double stepX = Math.Abs(xmin - xmax)/(pbx.Width);
for(int i = 0; i < pbx.Width; i++)
{
y = ymin;
for(int j = 0; j < pbx.Height; j++)
{
double rez = x;
double imz = y;
int iter = 0;
while(rez * rez + imz * imz <= 4 && iter < MAX)
{
rez = rez * rez - imz * imz + x;
imz = 2 * rez * imz + y;
iter++;
}
if(iter == MAX)
{
p.Color = Color.Black;
g.DrawRectangle(p, i, j, 1, 1);
}
else
{
p.Color = Color.White;
g.DrawRectangle(p, i, j, 1, 1);
}
y += stepY;
}
x += stepX;
}
}
please help me my mind is getting crushed thinking how to get the beautiful mandlebrot set...
and sorry if i committed some mistakes but English is not my speaked language!
You have some irregularities elsewhere. The range you're plotting isn't the entire set, and I would calculate x and y directly for each pixel, rather than using increments (so as to avoid rounding error accumulating).
But it looks to me as though your main error is in the iterative computation. You are modifying the rez variable before you use it in the computation of the new imz value. Your loop should look more like this:
while(rez * rez + imz * imz <= 4 && iter < MAX)
{
double rT = rez * rez - imz * imz + x;
imz = 2 * rez * imz + y;
rez = rT;
iter++;
}
Additionally to Peters answer, you should use a color palette instead of drawing just black and white pixels.
Create a array of colors, like this: (very simple example)
Color[] colors = new Colors[768];
for (int i=0; i<256; i++) {
colors[i ]=Color.FromArgb( i, 0, 0);
colors[i+256]=Color.FromArgb(255-i, i, 0);
colors[i+512]=Color.FromArgb(0 , 255-i, i);
}
Then use the iter value to pull a color and draw it:
int index=(int)((double)iter/MAX*767);
p.Color c = colors[index];
g.DrawRectangle(p, i, j, 1, 1);
Replace the entire if (iter == MAX) ... else ... statement with this last step.
Related
Take a look at this source code. A 3x3 Sharpen filter with the following kernel
0 -1 0
-1 5 -1
0 -1 0
gives the following output:
I tried to replicate the outcome using my own code which is pretty much straight forward:
public partial class FilterForm : Form
{
public FilterForm()
{
InitializeComponent();
Bitmap image = (Bitmap)Bitmap.FromFile("lena.jpg");
InputPictureBox.Image = image;
double[,] dImage = ToDouble2d(image);
double[,] dMask = { { 0,-1, 0, },
{ -1, 5, -1, },
{ 0,-1, 0, }, };
double[,]dConv = LinearConvolutionSpatial(dImage, dMask);
Bitmap conv = ToBitmap2d(dConv, PixelFormat.Format32bppArgb);
OutputPictureBox.Image = conv;
}
public double[,] ToDouble2d(Bitmap input)
{
int width = input.Width;
int height = input.Height;
double[,] array2d = new double[width, height];
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
Color cl = input.GetPixel(x, y);
double gray = ((cl.R * 0.3) + (cl.G * 0.59) + (cl.B * 0.11));
array2d[x, y] = gray / 255.0;
}
}
return array2d;
}
public Bitmap ToBitmap2d(double[,] image, PixelFormat pixelFormat)
{
int Width = image.GetLength(0);
int Height = image.GetLength(1);
Bitmap bmp = new Bitmap(Width, Height, pixelFormat);
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
int i = (int)(image[x, y] * 255.0);
if (i > 255) i = 255;
if (i < 0) i = 0;
Color clr = Color.FromArgb(i, i, i);
bmp.SetPixel(x, y, clr);
}
}
return bmp;
}
private double[,] LinearConvolutionSpatial(double[,] paddedImage, double[,] mask)
{
int paddedImageWidth = paddedImage.GetLength(0);
int paddedImageHeight = paddedImage.GetLength(1);
int maskWidth = mask.GetLength(0);
int maskHeight = mask.GetLength(1);
int imageWidth = paddedImageWidth - maskWidth;
int imageHeight = paddedImageHeight - maskHeight;
double[,] convolve = new double[imageWidth, imageHeight];
for (int y = 0; y < imageHeight; y++)
{
for (int x = 0; x < imageWidth; x++)
{
double sum = Sum(paddedImage, mask, x, y);
int xxx = x;
int yyy = y;
convolve[xxx, yyy] = sum;
string str = string.Empty;
}
}
Rescale(convolve);
return convolve;
}
double Sum(double[,] paddedImage1, double[,] mask1, int startX, int startY)
{
double sum = 0;
int maskWidth = mask1.GetLength(0);
int maskHeight = mask1.GetLength(1);
for (int y = startY; y < (startY + maskHeight); y++)
{
for (int x = startX; x < (startX + maskWidth); x++)
{
double img = paddedImage1[x, y];
double msk = mask1[maskWidth - x + startX - 1, maskHeight - y + startY - 1];
sum = sum + (img * msk);
}
}
return sum;
}
void Rescale(double[,] convolve)
{
int imageWidth = convolve.GetLength(0);
int imageHeight = convolve.GetLength(1);
double minAmp = 0.0;
double maxAmp = 0.0;
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
minAmp = Math.Min(minAmp, convolve[i, j]);
maxAmp = Math.Max(maxAmp, convolve[i, j]);
}
}
double scale = 1 / (Math.Abs(minAmp) + maxAmp);
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
double d = (convolve[i, j] + Math.Abs(minAmp)) * scale;
convolve[i, j] = d;
}
}
}
}
But, the problem I am facing is, my output has a different contrast.
What points I should work on?
Some of the above code has a min/max effect and balances the histogram.
Remove the normalizing bit from this line:
array2d[x, y] = gray;// / 255.0;
I've removed the rescale multiplier of 255 in this piece:
public Bitmap ToBitmap2d(double[,] image, PixelFormat pixelFormat)
{
int Width = image.GetLength(0);
int Height = image.GetLength(1);
Bitmap bmp = new Bitmap(Width, Height, pixelFormat);
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
int i = (int)(image[x, y] * 1);
if (i > 255) i = 255;
if (i < 0) i = 0;
Color clr = Color.FromArgb(i, i, i);
bmp.SetPixel(x, y, clr);
}
}
return bmp;
}
And I've also removed the scaling factor from this function:
void Rescale(double[,] convolve)
{
int imageWidth = convolve.GetLength(0);
int imageHeight = convolve.GetLength(1);
double minAmp = 0.0;
double maxAmp = 255.0;
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
minAmp = Math.Min(minAmp, convolve[i, j]);
maxAmp = Math.Max(maxAmp, convolve[i, j]);
}
}
double scale = 1 / (Math.Abs(minAmp) + maxAmp);
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
double d = (convolve[i, j]);// + Math.Abs(minAmp)) * scale;
convolve[i, j] = d;
}
}
}
Appears to work as intended after those changes are made, in this case.
I have found the solution from this link. The main clue was to introduce an offset and a factor.
factor is the sum of all values in the kernel.
offset is an arbitrary value to fix the output further.
The following source code is supplied in the given link:
private void SafeImageConvolution(Bitmap image, ConvMatrix fmat)
{
//Avoid division by 0
if (fmat.Factor == 0)
return;
Bitmap srcImage = (Bitmap)image.Clone();
int x, y, filterx, filtery;
int s = fmat.Size / 2;
int r, g, b;
Color tempPix;
for (y = s; y < srcImage.Height - s; y++)
{
for (x = s; x < srcImage.Width - s; x++)
{
r = g = b = 0;
// Convolution
for (filtery = 0; filtery < fmat.Size; filtery++)
{
for (filterx = 0; filterx < fmat.Size; filterx++)
{
tempPix = srcImage.GetPixel(x + filterx - s, y + filtery - s);
r += fmat.Matrix[filtery, filterx] * tempPix.R;
g += fmat.Matrix[filtery, filterx] * tempPix.G;
b += fmat.Matrix[filtery, filterx] * tempPix.B;
}
}
r = Math.Min(Math.Max((r / fmat.Factor) + fmat.Offset, 0), 255);
g = Math.Min(Math.Max((g / fmat.Factor) + fmat.Offset, 0), 255);
b = Math.Min(Math.Max((b / fmat.Factor) + fmat.Offset, 0), 255);
image.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
}
I am calculating values by using weights and bias from MATLAB trained ANN. trying to code a sigmoid simulation equation, but for some reason C# calculations vary too much than that of MATLAB. i.e. error is too high. I tried to check each step of the equation and found out the specific part that is creating the problem (Emphasized part), but I don't know how to solve this issue, if someone could help, would be a huge favour.
1+(purelin(net.LW{2}×(tansig(net.IW{1}×(1-(abs(2×([inputs]-1)))))+net.b{1}))+net.b{2}))/2
//Normalization of Data
public double Normalization(double x, double xMAx, double xMin)
{
double xNorm = 0.0;
xNorm = (x - xMin) / (xMAx - xMin);
if (xNorm < 0)
xNorm = 0;
if (xNorm > 1)
xNorm = 1;
xNorm = Math.Round(xNorm, 4);
return xNorm;
}
// Equation to calculate ANN based Output Values
public double MetrixCalc(double[] Pn, double[,] W1, double[] W2, double[] b1, double b2, double maxValue, double minValue)
{
double FinalValue = 0;
double[] PnCalc1 = new double[Pn.Length];
double[] PnCalc2 = new double[W1.Length / Pn.Length];
for (int i = 0; i < Pn.Length; i++)
{
PnCalc1[i] = 1 - Math.Abs(2 * (Pn[i] - 1));
}
for (int i = 0; i < (W1.Length / Pn.Length); i++)
{
double PnCalc = 0.0;
for (int j = 0; j < Pn.Length; j++)
{
PnCalc = PnCalc + (W1[i, j] * PnCalc1[j]);
}
PnCalc2[i] = PnCalc;
}
for (int i = 0; i < PnCalc2.Length; i++)
{
//PnCalc2[i] = Math.Tanh(PnCalc2[i] + b1[i]);
PnCalc2[i] = PnCalc2[i] + b1[i];
PnCalc2[i] = 2.0 / (1 + Math.Exp(-2 * (PnCalc2[i]))) - 1;
PnCalc2[i] = Math.Round(PnCalc2[i], 4);
}
double FinalCalc = 0.0;
for (int i = 0; i < PnCalc2.Length; i++)
{
*FinalCalc = FinalCalc + (W2[i] * (PnCalc2[i]));*
//FinalValue = FinalCalc;
}
FinalValue = FinalCalc + b2;
FinalValue = 1 + FinalValue;
FinalValue = (1 + FinalValue) / 2.0;
FinalValue = (FinalValue * (maxValue - minValue)) + minValue;
FinalValue = Math.Round(FinalValue, 4);
FinalValue = Math.Abs(FinalValue);
return FinalValue;
}
Problem is solved.
Problem was with the weights matrix copied from MATLAB. debugging mode saved my life. :)
I have got this method to get a polynomial with my desired degree:
public static double[] Polyfit(double[] x, double[] y, int degree)
{
// Vandermonde matrix
var v = new DenseMatrix(x.Length, degree + 1);
for (int i = 0; i < v.RowCount; i++)
for (int j = 0; j <= degree; j++) v[i, j] = Math.Pow(x[i], j);
var yv = new DenseVector(y).ToColumnMatrix();
QR qr = v.QR();
// Math.Net doesn't have an "economy" QR, so:
// cut R short to square upper triangle, then recompute Q
var r = qr.R.SubMatrix(0, degree + 1, 0, degree + 1);
var q = v.Multiply(r.Inverse());
var p = r.Inverse().Multiply(q.TransposeThisAndMultiply(yv));
Console.WriteLine(p.Column(0).ToString());
return p.Column(0).ToArray();
}
How can I feed the method above with values from my chart (x and y)?
chart.Series[0].Points.... ?
I think you need this:
chart1.Series[0].YValueMembers
chart1.Series[0].XValueMember
The Points property is a getter, so you cannot set a new instance of DataPointCollection to it. You should however be able to access methods on the current DataPointCollection.
You could try something along the lines of:
chart.Series[0].Points.AddXY(double, double)
You would then iterate the array(s) and set the points manually.
MSDN DataPointCollection for more information.
A working solution is:
////generate polynomial of degree 4 fiting to the points
double[] arrayX = new double[chart.Series[0].Points.Count()];
double[] arrayY = new double[chart.Series[0].Points.Count()];
double[] arrayResult = { };
for (int i = 0; i < chart.Series[0].Points.Count(); i++)
{
arrayX[i] = chart.Series[0].Points[i].XValue;
arrayY[i] = chart.Series[0].Points[i].YValues[0];
}
arrayResult = Polyfit(arrayX, arrayY, 4);
foreach (double element in arrayResult)
{
MessageBox.Show(element.ToString());
}
double functionVarE = arrayResult[0];
double functionVarD = arrayResult[1];
double functionVarC = arrayResult[2];
double functionVarB = arrayResult[3];
double functionVarA = arrayResult[4];
double equationVar = 0;
//prepare the function series in the graph
if (chart.Series.IndexOf("function") < 0)
chart.Series.Add("function");
chart.Series[2].Points.Clear();
chart.Series[2].ChartType = SeriesChartType.Line;
for (int x = -500; x < 1000; x++) //hardcoding
{
equationVar = functionVarA * (Math.Pow(x, 4)) + functionVarB * (Math.Pow(x, 3)) + functionVarC * (Math.Pow(x, 2)) + functionVarD * x + functionVarE;
chart.Series[2].Points.AddXY(Convert.ToDouble(x), equationVar);
}
This is a working solution I coded. If you see any improvement feel free to tell me!
I am working on a homography method to copy and expand the relevant points from a rectangle area of depthImg array to a new array, but the bottomright points do not change the homographyImg array. Any ideas, suggestions appreciated. Thanks and happy holidays.
public short[] depthImg;
public int topleftx = 10;
public int toplefty = 20;
public int toprightx = 300;
public int toprighty = 20;
public int bottomleftx = 30;
public int bottomlefty = 200;
public int bottomrightx = 310;
public int bottomrighty = 220;
short[] homographyImg = new short[320 * 240];
for(int ii = 0; ii < 320 * 240; ii++)
{
int xx = ii % 320;
int yy = ii / 320;
int lx =(topleftx + (bottomleftx - topleftx)*(yy/240));
int rx =(toprightx + (bottomrightx - toprightx)*(yy/240));
if (xx < rx & xx > lx)
{
int px = 320*(xx-lx)/(rx-lx);
int ty =(toplefty + (toprighty - toplefty)*(px/320));
int by =(bottomlefty + (bottomrighty - bottomlefty)*(px/320));
if (yy > ty & yy < by)
{
int pxy = 240*(yy-ty)/(by-ty)*320 + px;
homographyImg[pxy] = depthImg[ii];
}
}
}
// I couldn't paste code in the conversation, so I uploaded here. This is a similar array transformation where they modify the corner coordinates to get a correct picture.
for(int yy = 0; yy < newHeight; yy++)
{
for(int xx = 0; xx < newWidth; xx++)
{
int TLidx = (xx * 2) + yy * 2 * width;
int TRidx = (xx * 2 + 1) + yy * width * 2;
int BLidx = (xx * 2) + (yy * 2 + 1) * width;
int BRidx = (xx * 2 + 1) + (yy * 2 + 1) * width;
dst[newWidth- xx - 1 + yy * newWidth] = Color32.Lerp(Color32.Lerp(src[BLidx],src[BRidx],.5F),
Color32.Lerp(src[TLidx],src[TRidx],.5F),.5F);
}
}
I need to implement Single Scale retinex and multiscale retinex algorithm in C#,
I searched a bit but couldn't find any useful practice projects and artilces with code
As I understood correctly I should:
Convert RGB to YUV
Blur the image using Gaussian blur filter
Use I'(x, y) = 255*log10( I(x, y)/G(x, y) ) + 127.5
I - is illumination, G - Gaussian kernel, I' - the result image
Сonvert back YUV to RGB
This code is not working correctly
public static Image<Bgr, byte> SingleScaleRetinex(this Image<Bgr, byte> img, int gaussianKernelSize, double sigma)
{
var radius = gaussianKernelSize / 2;
var kernelSize = 2 * radius + 1;
var ycc = img.Convert<Ycc, byte>();
var sum = 0f;
var gaussKernel = new float[kernelSize * kernelSize];
for (int i = -radius, k = 0; i <= radius; i++, k++)
{
for (int j = -radius; j <= radius; j++)
{
var val = (float)Math.Exp(-(i * i + j * j) / (sigma * sigma));
gaussKernel[k] = val;
sum += val;
}
}
for (int i = 0; i < gaussKernel.Length; i++)
gaussKernel[i] /= sum;
var gray = new Image<Gray, byte>(ycc.Size);
CvInvoke.cvSetImageCOI(ycc, 1);
CvInvoke.cvCopy(ycc, gray, IntPtr.Zero);
// Размеры изображения
var width = img.Width;
var height = img.Height;
var bmp = gray.Bitmap;
var bitmapData = bmp.LockBits(new Rectangle(Point.Empty, gray.Size), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
unsafe
{
for (var y = 0; y < height; y++)
{
var row = (byte*)bitmapData.Scan0 + y * bitmapData.Stride;
for (var x = 0; x < width; x++)
{
var color = row + x;
float val = 0;
for (int i = -radius, k = 0; i <= radius; i++, k++)
{
var ii = y + i;
if (ii < 0) ii = 0; if (ii >= height) ii = height - 1;
var row2 = (byte*)bitmapData.Scan0 + ii * bitmapData.Stride;
for (int j = -radius; j <= radius; j++)
{
var jj = x + j;
if (jj < 0) jj = 0; if (jj >= width) jj = width - 1;
val += *(row2 + jj) * gaussKernel[k];
}
}
var newColor = 127.5 + 255 * Math.Log(*color / val);
if (newColor > 255)
newColor = 255;
else if (newColor < 0)
newColor = 0;
*color = (byte)newColor;
}
}
}
bmp.UnlockBits(bitmapData);
CvInvoke.cvCopy(gray, ycc, IntPtr.Zero);
CvInvoke.cvSetImageCOI(ycc, 0);
return ycc.Convert<Bgr, byte>();
}
Look at:
http://www.fer.unizg.hr/ipg/resources/color_constancy
These algorithms are modifications of the Retinex algorithm (with speed improvement) although the author gave them funny names :)
There is a full source code (C++, but it is written very nicely).
Sorry for necro-posting, but it seems that there's a mistake in step 3 of your procedure that can mislead someone passing by.
In order to apply the correction, you want to divide source image by Gauss-filtered copy of it, not the Gaussian kernel itself. Approximately, in pseudo-code:
I_filtered(x,y) = G(x,y) * I(x,y)
I'(x,y) = log(I(x,y) / I_filtered(x,y))
And then apply casting of I'(x,y) to required numeric type (uint8, as I can refer from original post).
More on that topic can be found in this paper:
Ri(x, y) = log(Ii(x, y)) − log(Ii(x, y) ∗ F(x, y))
where Ii
is the input image on the i-th color channel, Ri
is the retinex output image on the i-th
channel and F is the normalized surround function.
.