Apply mask to image - c#

I need to apply mask (3x3) to image manually by iterating through it and calculating new values for each pixel. My code seems to work, but there is an issue - new value might not be between 0 and 255, it can be higher or lower. Such values are not acceptable. And now I don't know how to correctly solve it.
Apparently normalization to 0-255 will work, but here I need to normalize whole set of values which are known after loop is finished. This means I need to iterate through entire image twice.
You can also rate my code, maybe something can be improved, and maybe it actually doesn't work correctly despite compiling and creating processed images.
public Image<Rgba32> ApplyMask3x3(int[,] mask, Image<Rgba32> image)
{
Image<Rgba32> result = new Image<Rgba32>(image.Width, image.Height);
for(int row = 0; row < image.Height; row++)
{
for(int col = 0; col < image.Width; col++)
{
byte R = 0, G = 0, B = 0;
//temporary - forcefully throw new values to 0-255
int valR = ApplyMaskR3x3(col, row, image, mask); //code below
int valG = ApplyMaskG3x3(col, row, image, mask); //identical code as R but uses G attribute
int valB = ApplyMaskB3x3(col, row, image, mask); //identical code as R but uses B attribute
if (valR > 255) valR = 255;
if (valR < 0) valR = 0;
if (valG > 255) valG = 255;
if (valG < 0) valG = 0;
if (valB > 255) valB = 255;
if (valB < 0) valB = 0;
R = Convert.ToByte(valR);
G = Convert.ToByte(valG);
B = Convert.ToByte(valB); ;
result[col, row] = new Rgba32(R,G,B);
}
}
return result;
}
private int ApplyMaskR3x3(int col, int row, Image<Rgba32> image, int[,] mask)
{
int a, b, c;
int d, e, f;
int g, h, i;
if (col == 0 || row == 0)
a = 0;
else
a = image[col - 1, row - 1].R * mask[0, 0];
if (row == 0)
b = 0;
else
b = image[col, row - 1].R * mask[0, 1];
if (row == 0 || col == image.Width - 1)
c = 0;
else
c = image[col + 1, row - 1].R * mask[0, 2];
if (col == 0)
d = 0;
else
d = image[col - 1, row].R * mask[1, 0];
e = image[col, row].R * mask[1, 1];
if (col == image.Width - 1)
f = 0;
else
f = image[col + 1, row].R * mask[1, 2];
if (col == 0 || row == image.Height - 1)
g = 0;
else
g = image[col - 1, row + 1].R * mask[2, 0];
if (row == image.Height - 1)
h = 0;
else
h = image[col, row + 1].R * mask[2, 1];
if (col == image.Width - 1 || row == image.Height - 1)
i = 0;
else
i = image[col + 1, row + 1].R * mask[2, 2];
return a + b + c + d + e + f + g + h + i;
}

You should be able to make use of the Filter processor built in to ImageSharp
From your code sample you should be able to do this
public Image<Rgba32> ApplyMask3x3(int[,] mask, Image<Rgba32> image)
{
var matrix = new ColorMatrix(
mask[0,0],
mask[0,1],
mask[0,2],
mask[1,0],
mask[1,1],
mask[1,2],
mask[2,0],
mask[2,1],
mask[2,2]
);
image.Mutate(x=>x.Filter(matrix));
return image;
}
replace .Mutate() with .Clone() if you actually need a 2nd image and don't want to mutate in place.
If you Clone you need to make sure that both source and output images are disposed of correctly otherwise you can end up causing memory issues.

Related

How to get the neighbours of a cell in a matrix in C#

I tried to print the neighbours of any given cell by using its row index and column index in a 2D array using the following method:
public static List<int[,]> getAUVNieghborsCells(int [,] grid, int row, int col)
{
List<int[,]> n = new List<int[,]>();
//define boundaries
int rowLen = Math.Min(row + 1, grid.GetLength(0) - 1),
colLen = Math.Min(col + 1, grid.GetLength(1) - 1),
rowIdx = Math.Max(0, row - 1),
colIdx = Math.Max(0, col - 1);
for (int i = rowIdx; i <= rowLen; i++)
{
for (int j = colIdx; j <= colLen; j++)
{
//if it is our given index, continue
if (i == row && j == col)
continue;
int[,] temp = new int[1, 2];
temp[0, 0] = i;
temp[0, 1] = j;
n.Add(temp);
}
}
return n;
}
I send (4,0) but I got:
|(4,0)||(4,1)||(5,1)||(6,0)||(6,1)|
which are wrong as they are the neighbors for (5,0) and (4,0). Where is the problem?
For me your code works well it generated (3,0);(3,1);(4,1);(5,0);(5,1) for the (4,0) input.
I wrote my own too and I get the same output.
private static List<int[,]> getNeigbores(int[,] matrix, int row, int column)
{
List<int[,]> result = new List<int[,]>();
int rowMinimum = row - 1 < 0 ? row : row - 1;
int rowMaximum = row + 1 > matrix.GetLength(0) ? row : row + 1;
int columnMinimum = column - 1 < 0 ? column : column - 1;
int columnMaximum = column + 1 > matrix.GetLength(1) ? column : column + 1;
for (int i = rowMinimum; i <= rowMaximum; i++)
for (int j = columnMinimum; j <= columnMaximum; j++)
if (i != row || j != column)
result.Add(new int[1, 2] { { i, j } });
return result;
}
Does the following code fits your needs?
Int32 targX = 4;
Int32 targY = 0;
Point targ = new Point(targX, targY);
List<Point> neighbours = (from x in Enumerable.Range(targX - 1, 3)
from y in Enumerable.Range(targY - 1, 3)
where (x >= 0) && (x < grid.GetLength(0)) && (y >= 0) && (y < grid.GetLength(1))
select new Point(x, y))
.Where(p => p != targ).ToList();
Demo code here.

mandlebrot fractal error in the plotted function

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.

Average value of array elements

I am trying to calculate the value of a single dimensional Array, here is my code:
So when I click "Detect", it should start a threshold through my Image, beginning from i = 0 to Image height and from j = 0 to Image width:
public void detektieren_Click(object sender, RoutedEventArgs e)
{
for (i = 0; i < bitmap.Height; i++)
{
for (j = 0; j < bitmap.Width; j++)
{
stride = bitmap.PixelWidth * (bitmap.Format.BitsPerPixel / 8);
data = new byte[stride * bitmap.PixelHeight];
bitmap.CopyPixels(data, stride, 0);
index = i * stride + 4 * j;
Now accessing the ARGB data:
byte A = data[index + 3];
byte R = data[index + 2];
byte G = data[index + 1];
byte B = data[index];
After the threshold, if there are any Pixels meet the condition R=0 & G=0 & B=255:
if (Convert.ToInt32(R) == 0 && Convert.ToInt32(G) == 0 && Convert.ToInt32(B) == 255)
{
// Create a writer and open the file:
StreamWriter Messdaten;
if (!File.Exists("C:/Users/.../Messdaten.csv"))
{
Messdaten = new StreamWriter("C:/Users/.../Messdaten.csv");
}
else
{
Messdaten = File.AppendText("C:/Users/.../Messdaten.csv");
}
// Write to the file:
Messdaten.WriteLine(j + ";" + i);
// Close the stream:
Messdaten.Close();
for (y = 0; y < bitmap.Height; y++)
{
for (x = 0; x < bitmap.Width; x++)
{
double x_mw = 0; double y_mw = 0;
int[] x_array = new int[(int)bitmap.Width];
int[] y_array = new int[(int)bitmap.Height];
x_array[x] = j;
x_mw = x_array.Average();
y_array[y] = i;
y_mw = y_array.Average();
xy_coord.Content = (int) x_mw + ";" + (int) y_mw;
}
}
}
}
}
}
Everything works perfectly in the CSV file, I can detect a Pixel (e.g. blue with R=0 G=0 B=255). But I also want to copy the data of each single Pixel into Array. But apparently it doesn't really deliver what I want. It doesn't calculate the average value of sum of blue Pixels (= the centroid of the blue Pixels scatter), instead it just Shows x_mw = 0 and y_mw = 0. What did I do wrong?
After I did some modification it works. So this is the code:
public void detektieren_Click(object sender, RoutedEventArgs e)
{
int x_sum = 0; int y_sum = 0; int x_count = 0; int y_count = 0; int x_mw; int y_mw;
int[] x_array = new int[(int)bitmap.Width];
int[] y_array = new int[(int)bitmap.Height];
int[] x_array_copy = new int[(int)bitmap.Width];
int[] y_array_copy = new int[(int)bitmap.Height];
stride = bitmap.PixelWidth * (bitmap.Format.BitsPerPixel / 8);
data = new byte[stride * bitmap.PixelHeight];
bitmap.CopyPixels(data, stride, 0);
for (i = 0; i < (int) bitmap.Height; i++)
{
for (j = 0; j < (int) bitmap.Width; j++)
{
index = i * stride + 4 * j;
byte A = data[index + 3];
byte R = data[index + 2];
byte G = data[index + 1];
byte B = data[index];
if (Convert.ToInt32(R) == 0 && Convert.ToInt32(G) == 0 && Convert.ToInt32(B) == 255)
{
x_array[j] = j;
x_count++;
x_array_copy[j] = x_array_copy[j] + j;
x_sum = (int) x_array_copy.Sum();
x_mw = x_sum / x_count;
y_array[i] = i;
y_count++;
y_array_copy[i] = y_array_copy[i] + i;
y_sum = (int) y_array_copy.Sum();
y_mw = y_sum / y_count;
xy_coord.Content = x_mw + ";" + y_mw;
}
}
}
}

Retinex algorithm implementation

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.
.

c# combining two images, that contain parts of each other

I have 2 pictures, containing part of each other:
now I want to combine them together, but not repeating the common part, to have something like that:
What is the best way to do it?
#edit: That images are only examples of what I want to do with any two images, that contain part of each other, and that part is at the bottom of the first image, and at the top of the second.
here's a solution for your question :
I defined a function which takes 2 Bitmaps and returns the Combined Bitmap
, in this function , I store first 2 rows of the second bitmap in an array of byte so I can compare them with the first bitmap in the next step , then I start looking for the matched rows in the first bitmap whenever I fined the matched row in that , I store the y position
, now I combine those bitmaps according to the y I've already found !
Here's the Demo Project : Download
Here's the Solution File : Download
here's the results for :
Example 1
Example 2
and here's the function :
private Bitmap CombineImages(Bitmap bmp_1, Bitmap bmp_2)
{
if (bmp_1.Width == bmp_2.Width)
{
int bmp_1_Height, bmpWidth, bmp_2_Height;
bmpWidth = bmp_1.Width;
bmp_1_Height = bmp_1.Height;
bmp_2_Height = bmp_2.Height;
Color c;
bool notFound = false;
int firstMatchedRow = 0;
byte[,] bmp2_first2rows = new byte[3 * bmpWidth, 2];
for (int b = 0; b < 2; b++)
{
for (int a = 0; a < bmpWidth; a++)
{
c = bmp_2.GetPixel(a, b);
bmp2_first2rows[a * 3, b] = c.R;
bmp2_first2rows[a * 3 + 1, b] = c.G;
bmp2_first2rows[a * 3 + 2, b] = c.B;
}
}
for (int y = 0; y < bmp_1_Height - 1; y++)
{
for (int j = 0; j < 2; j++)
{
for (int x = 0; x < bmpWidth; x++)
{
c = bmp_1.GetPixel(x, y + j);
if ((bmp2_first2rows[x * 3, j] == c.R) &&
(bmp2_first2rows[x * 3 + 1, j] == c.G) &&
(bmp2_first2rows[x * 3 + 2, j] == c.B))
{
}
else
{
notFound = true;
break;
}
}
if (notFound)
{
break;
}
}
if (!notFound)
{
firstMatchedRow = y;
break;
}
else
{
notFound = false;
}
}
if (firstMatchedRow > 0)
{
Bitmap bmp = new Bitmap(bmpWidth, firstMatchedRow + bmp_2_Height);
Graphics g = Graphics.FromImage(bmp);
Rectangle RectDst = new Rectangle(0, 0, bmpWidth, firstMatchedRow);
Rectangle RectSrc;
g.DrawImage(bmp_1, RectDst, RectDst, GraphicsUnit.Pixel);
RectDst = new Rectangle(0, firstMatchedRow, bmpWidth, bmp_2_Height);
RectSrc = new Rectangle(0, 0, bmpWidth, bmp_2_Height);
g.DrawImage(bmp_2, RectDst, RectSrc, GraphicsUnit.Pixel);
return bmp;
}
else
{
return null;
}
}
else
{
return null;
}
}
And Finally I should mention that , these Fantastic Tutorials have Helped me a lot in Image Processing :
Image Processing for Dummies with C# and GDI+
Image Processing using C#
Hope it Helps :)

Categories