Compare 2 16x16 pixel images similarity - c#

I would like to compare 2 images similarity with percentage. I want to detect 90% same images. Each image size is 16x16 pixel. I need some clue, help about it. Right now i am able to detect 100% same images when comparing with the code below
for (; x < irMainX; x++)
{
for (; y < irMainY; y++)
{
Color pixelColor = image.GetPixel(x, y);
if (pixelColor.A.ToString() != srClickedArray[x % 16, y % 16, 0])
{
blSame = false;
y = 16;
break;
}
if (pixelColor.R.ToString() != srClickedArray[x % 16, y % 16, 1])
{
blSame = false;
y = 16;
break;
}
if (pixelColor.G.ToString() != srClickedArray[x % 16, y % 16, 2])
{
blSame = false;
y = 16;
break;
}
if (pixelColor.B.ToString() != srClickedArray[x % 16, y % 16, 3])
{
blSame = false;
y = 16;
break;
}
}
y = y - 16;
if (blSame == false)
break;
}
For example i would like to recognize these 2 images as same. Currently the software recognizes them as different images since they are not exactly same

Use a count for the number of pixels that don't match:
public const double PERCENT_MATCH = 0.9;
int noMatchCount = 0;
for (int x = 0; x < irMainX; x++)
{
for (int y = 0; y < irMainY; y++)
{
if ( !pixelsMatch( image.GetPixel(x,y), srClickedArray[x%16, y%16] )
{
noMatchCount++;
if ( noMatchCount > ( 16 * 16 * ( 1.0 - PERCENT_MATCH ))
goto matchFailed;
}
}
}
Console.WriteLine("images are >=90% identical");
return;
matchFailed:
Console.WriteLine("image are <90% identical");
You could count matching pixels, but that will be slower. Consider measuring how much two pixels differ. For most purposes - you could have ALL the pixels not match exactly - yet have the images look visually identical

I wouldn't use image.GetPixel(x,y), as it's a lot slower than utilizing unsafe code to check specific bytes associated with each image.
Check out Lockbits

Related

how to set the SetAlphamaps to one certain texture?

i want to change the texture of my terrain with certain texture. i got confuse to set the splatmapdata, anyone can help me out??
private void ChangeTexture(Vector3 WorldPos)
{
print ("changeTexture");
int mapX = (int)(((WorldPos.x - terrainPos.x) / terrainData.size.x) * terrainData.alphamapWidth);
int mapZ = (int)(((WorldPos.z - terrainPos.z) / terrainData.size.z) * terrainData.alphamapHeight);
float[,,] splatmapData = terrainData.GetAlphamaps(3, 3, 15, 15);
terrainData.SetAlphamaps (mapX, mapZ, splatmapData);
terrain.Flush ();
}
The data returned by GetAlphamaps
The returned array is three-dimensional - the first two dimensions represent x and y coordinates on the map, while the third denotes the splatmap texture to which the alphamap is applied.
Or in simple words a float[x, y, l] where
x = width in pixels
y = height in pixels
l = Texture-Layer
So lets say you want to set it to a certain texture at this pixel coordinates what you do is
set the weight for the texture's layer to 1
set all other layers weight to 0
So let's say you have e.g. 3 Layers and you want the second one (= index 1) to be the full weighted texture:
float[,,] splatmapData = terrainData.GetAlphamaps(mapX, mapZ, 15, 15);
// Iterate over x-y coordinates within the array
for(var y = 0; i < 15; y++)
{
for(var x = 0; x < 15; x++)
{
// Set first layers weight to 0
splatmapData[x, y, 0] = 0;
// Set second layer's weight to 1
splatmapData[x, y, 1] = 1;
// Set third layer's weight to 0
splatmapData[x, y, 2] = 0;
}
}
terrainData.SetAlphamaps(mapX, mapZ, splatmapData);
I would then implement an enum for the layers like let's say
public enum TerrainLayer
{
Default = 0,
Green,
Red
}
so you can simply pass the according layer index as a parameter - a bit more secure than passing in the int values themselves:
private void ChangeTexture(Vector3 worldPos, TerrainLayer toLayer)
{
print ("changeTexture");
int mapX = (int)(((worldPos.x - terrainPos.x) / terrainData.size.x) * terrainData.alphamapWidth);
int mapZ = (int)(((worldPos.z - terrainPos.z) / terrainData.size.z) * terrainData.alphamapHeight);
float[,,] splatmapData = terrainData.GetAlphamaps(mapX, mapZ, 15, 15);
for(var z = 0; z < 15; z++)
{
for(var x = 0; x < 15; x++)
{
// This ofcourse would be more efficient if you do this only once
// e.g. in Awake since the enum won't change on runtime
var values = (TerrainLAyer[])Enum.GetValues(typeof(TerrainLayer));
// Iterate through the enum and
for(var l = 0; l < values.Length; l++)
{
// set all layers to 0 except the toLayer
splatmapData[x, z, l] = values[l] == toLayer ? 1 : 0;
}
}
}
terrainData.SetAlphamaps (mapX, mapZ, splatmapData);
terrain.Flush ();
}
Now you would simply call it e.g.
ChangeTexture(somePosition, TerrainLayer.Green);

Algorithm to scale down YUV 4:2:2

Trying to write an efficient algorithm to scale down YUV 4:2:2 by a factor of 2 - and which doesn't require a conversion to RGB (which is CPU intensive).
I've seen plenty of code on stack overflow for YUV to RGB conversion - but only an example of scaling for YUV 4:2:0 here which I have started based my code on. However, this produces an image which is effectively 3 columns of the same image with corrupt colours, so something is wrong with the algo when applied to 4:2:2.
Can anybody see what is wrong with this code?
public static byte[] HalveYuv(byte[] data, int imageWidth, int imageHeight)
{
byte[] yuv = new byte[imageWidth / 2 * imageHeight / 2 * 3 / 2];
int i = 0;
for (int y = 0; y < imageHeight; y += 2)
{
for (int x = 0; x < imageWidth; x += 2)
{
yuv[i] = data[y * imageWidth + x];
i++;
}
}
for (int y = 0; y < imageHeight / 2; y += 2)
{
for (int x = 0; x < imageWidth; x += 4)
{
yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + x];
i++;
yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + (x + 1)];
i++;
}
}
return yuv;
}
A fast way to generate a low quality thumbnail would be to discard half of the data in each dimension.
We break the image in 4x2 grid of pixels - each pair of pixels in the grid is represented by 4 bytes. In the down-scaled image, we take the color values for the first 2 pixels in the grid by copying the first 4 bytes, whilst discarding the other 12 bytes worth of data.
This scaling can be generalized to any power of 2 (1/2, 1/4, 1/8, ...) - this method is quick because it doesn't use any interpolation. This will give a lower quality image which appears blocky however - for better results consider some sampling approach.
public static byte[] FastResize(
byte[] data,
int imageWidth,
int imageHeight,
int scaleDownExponent)
{
var scaleDownFactor = (uint)Math.Pow(2, scaleDownExponent);
var outputImageWidth = imageWidth / scaleDownFactor;
var outputImageHeight = imageHeight / scaleDownFactor;
// 2 bytes per pixel.
byte[] yuv = new byte[outputImageWidth * outputImageHeight * 2];
var pos = 0;
// Process every other line.
for (uint pixelY = 0; pixelY < imageHeight; pixelY += scaleDownFactor)
{
// Work in blocks of 2 pixels, we discard the second.
for (uint pixelX = 0; pixelX < imageWidth; pixelX += 2*scaleDownFactor)
{
// Position of pixel bytes.
var start = ((pixelY * imageWidth) + pixelX) * 2;
yuv[pos] = data[start];
yuv[pos + 1] = data[start + 1];
yuv[pos + 2] = data[start + 2];
yuv[pos + 3] = data[start + 3];
pos += 4;
}
}
return yuv;
}
I assume that the original data is in the following order (as it seems so from your example code): First there are the luminance (Y) values of the pixels of the image (size = imageWidth*imageHeight bytes). After that there are the chrominance components UV, s.t., the values for a single pixel are given after each other. This means that the total size of the original image is 3*size.
Now for 4:2:2 subsampling means that every other value of the horizontal chrominance component are discarded. This reduces the data to size size + 0.5*size + 0.5*size = 2*size, i.e., luminance is kept completely and both chrominance components are divided to half. Therefore, the result image should be allocated as:
byte[] yuv = new byte[2*imageWidth*imageHeight];
As the first part of the image is copied in full the first loop becomes:
int i = 0;
for (int y = 0; y < imageHeight; y++)
{
for (int x = 0; x < imageWidth; x++)
{
yuv[i] = data[y * imageWidth + x];
i++;
}
}
Because this just copies the beginning of data this can be simplified to
int size = imageHeight*imageWidth;
int i = 0;
for (; i < size; i++)
{
yuv[i] = data[i];
}
Now to copy the rest we need to skip every other horizontal coordinate
for (int y = 0; y < imageHeight; y++)
{
for (int x = 0; x < imageWidth; x += 2) // +2 skip each other horizontal component
{
yuv[i] = data[size + y*2*imageWidth + 2*x];
i++;
yuv[i] = data[size + y*2*imageWidth + 2*x + 1];
i++;
}
}
The factor two in data-array index is needed because there are 2 bytes for each pixel (both chrominance components), so each "row" has 2*imageWidth bytes of data.

Using an IF statement inside loop vs outside the loop

i have a program with a nested nested nested loop (four loops altogether). I have a Boolean variable which i want to affect the code in the deepest loop and in the first nested loop a small amount. My dilemma is, i don't really want to have the if else statement put inside the loops as i would have thought that would check the Boolean's state every iteration using extra time to check the statement, and i know that the Boolean's state would not change when the loop starts. This lead me to think it would be better to place the if else statement outside the loops and just have my loops code slightly changed, however, this also looks messy there is a lot of repeated code.
One thing i thought might work, but of which i have little experience using, is a delegate, i could simply put some of the code in a method and then create a delegate, depending on the state of betterColor i could then assign that delegate methods with the different code on them beforehand, but this also seems messy.
Below is what i am trying to avoid as i thhought it may slow down my algorithm:
for (short y = 0; y < effectImage.Height; y++)
{
int vCalc = (y <= radius) ? 0 : y - radius;
for (short x = 0; x < effectImage.Width; x++)
{
int red = 0, green = 0, blue = 0;
short kArea = 0;
for (int v = vCalc; v <= y + radius && v < effectImage.Height; v++)
{
int calc = calcs[(y - v) + radius];
for (int h = (x <= calc || calc < 0) ? 0 : x - calc; h <= x + calc && h < effectImage.Width; h++)
{
if (betterColor == true)
{
red += colorImage[h, v].R * colorImage[h, v].R;
green += colorImage[h, v].G * colorImage[h, v].G;
blue += colorImage[h, v].B * colorImage[h, v].G;
kArea++;
}
}
}
if (betterColor == true)
effectImage.SetPixel(x, y, Color.FromArgb(red / kArea, green / kArea, blue / kArea));
else
effectImage.SetPixel(x, y, Color.FromArgb(Convert.ToInt32(Math.Sqrt(red / kArea)), Convert.ToInt32(Math.Sqrt(green / kArea)), Convert.ToInt32(Math.Sqrt(blue / kArea))));
}
if (y % 4 == 0) // Updates the image on screen every 4 y pixels calculated.
{
image.Image = effectImage;
image.Update();
}
}
And here is what my code now looks like:
if (betterColor == true)
{
for (short y = 0; y < effectImage.Height; y++)
{
int vCalc = (y <= radius) ? 0 : y - radius;
for (short x = 0; x < effectImage.Width; x++)
{
int red = 0, green = 0, blue = 0;
short kArea = 0;
for (int v = vCalc; v <= y + radius && v < effectImage.Height; v++)
{
int calc = calcs[(y - v) + radius];
for (int h = (x <= calc || calc < 0) ? 0 : x - calc; h <= x + calc && h < effectImage.Width; h++)
{
red += colorImage[h, v].R * colorImage[h, v].R;
green += colorImage[h, v].G * colorImage[h, v].G;
blue += colorImage[h, v].B * colorImage[h, v].G;
kArea++;
}
}
effectImage.SetPixel(x, y, Color.FromArgb(Convert.ToInt32(Math.Sqrt(red / kArea)), Convert.ToInt32(Math.Sqrt(green / kArea)), Convert.ToInt32(Math.Sqrt(blue / kArea))));
}
if (y % 4 == 0) // Updates the image on screen every 4 y pixels calculated.
{
image.Image = effectImage;
image.Update();
}
}
}
else
{
for (short y = 0; y < effectImage.Height; y++)
{
int vCalc = (y <= radius) ? 0 : y - radius;
for (short x = 0; x < effectImage.Width; x++)
{
int red = 0, green = 0, blue = 0;
short kArea = 0;
for (int v = vCalc; v <= y + radius && v < effectImage.Height; v++)
{
int calc = calcs[(y - v) + radius];
for (int h = (x <= calc || calc < 0) ? 0 : x - calc; h <= x + calc && h < effectImage.Width; h++)
{
red += colorImage[h, v].R;
green += colorImage[h, v].G;
blue += colorImage[h, v].B;
kArea++;
}
}
effectImage.SetPixel(x, y, Color.FromArgb(red / kArea, green / kArea, blue / kArea));
}
if (y % 4 == 0) // Updates the image on screen every 4 y pixels calculated.
{
image.Image = effectImage;
image.Update();
}
}
}
In terms of what the code does, it is a box blur that uses a circular kernal.
Moving the if out of the loop, and effectively duplicating the whole looping code is not really worth it. So if you have code like this:
for (i …)
{
if (something)
DoX(i);
else
DoY(i);
}
Then you should not replace it by this:
if (something)
{
for (i …)
DoX(i);
}
else
{
for (i …)
DoY(i);
}
Doing so will only make the code a lot more difficult to read and to maintain. One first need to figure out that this is actually the same code that’s being executed for each case (except that one tiny difference), and it’s super difficult to maintain once you need to change anything about the loop since you need to make sure that you edit both cases properly.
While in theory, performing a single check vs. performing that check N times is obviously faster, in practice, this rarely matters. If-branches that rely on a constant boolean are super fast, so if you calculate the condition outside of the loop (in your case betterColor is set outside the loop), then the performance difference will not be noticeable at all. In addition, branch prediction will usually make sure that there is no difference at all in these cases.
So no, don’t rewrite that code like that. Keep it the way that is more understandable.
In general, you should avoid these kind of micro optimizations anyway. It is very likely that you algorithm has much slower parts that are much more relevant to the overall performance than small constructs like that. So focusing on those small things which are already very fast will not help you make the total execution faster. You should only optimize things that are an actual performance bottleneck in your code, where a profiler showed that there is a performance issue or that optimizing that code will actively improve your performance. And stay away from optimizations that make code less readable unless you really need it (in most cases you won’t).
The way i see it, the code is not equivalent (in your first example if betterColor is false, nothing happens in the innermost loop).
But isn't this micro-optimizing?
You could probably do something with creating a function with a Func<> as argument for the innermost loop. And then pass the correct func depending on the betterColor value.
I.E. Blur(betterColor?FuncA:FuncB);
Although I don't think it will be faster then a boolean check... But that's my feeling.

Drawing square/game board c#

I want to create a simple square on C# which will be used as a game board.
I am trying to do it using nested loops and have looked into how people make squares this way however I am having difficulty understanding how its done.
This is my code so far for the board:
for (int x = 0; x < 8; x = x + 1)
for (int y = 0; y < 8; y = y + 1)
if (board[x, y] == SquareState.gotCheese)
Console.Write("C");
else
Console.Write("*");
It does print out a * if there is no cheese and a C is there is cheese on the board, however its all in a line and doesn't look like a board. Like this:
*****************C*******
This is the structure for the board if its any help
static SquareState[,] board = new SquareState[8, 8];
The fact that it is writing all in line is because you are now telling the console to create a new line. Console.write() just append strings inline with the precedent.
You for cycle should also be an y-first cycle, so you will cycle each horizontal value (x) and then pass to a new vertical one.
for (int y = 0; y < 8; y++){
for (int x = 0; x < 8; x++){
if (board[x, y] == SquareState.gotCheese)
Console.Write("C");
else
Console.Write("*");
}
Console.WriteLine();
}
If you don't swap the cycles your result will be wrong, for example in a 3 by 3 square where x goes from 0 to 2, from left to right and y goes from 0 to 2 from top to bottom, you will have:
External FOR entering x = 0
Internal FOR entering y = 0
writing the 'cell' (0, 0)
Internal FOR entering y = 1
writing the 'cell' (0, 1)
Internal FOR entering y = 2
writing the 'cell' (0, 2)
writing a new line
External FOR entering x = 1
...
The result of this will be:
(0,0)(0,1)(0,2)
(1,0)(1,1)(1,2)
(2,0)(2,1)(2,2)
That is wrong, it should be:
--------------------> x
(0,0)(1,0)(2,0) |
(0,1)(1,1)(2,1) |
(0,2)(1,2)(2,2) |
V y
You need to print a newline after the inner loop but inside the outer loop.
Console.WriteLine("");
for (int x = 0; x < 8; x = x + 1){
for (int y = 0; y < 8; y = y + 1){
if (board[x, y] == SquareState.gotCheese)
Console.Write("C");
else
Console.Write("*");
Console.WriteLine("");
}
}

How to changes doubles to a greyscale image?

I've created a 2d array of 1024 x 1024 values ranging from -1 to 1, but I do not know how I am supposed to change this to a greyscale image.
What I have been doing is assigning a certain color to certain values, but this is not what I was going for.
What I have:
Specific ranges of values between -1 and 1 are mapped to distinct colors in a noncontinuous way (see the code snippet below)
What I want:
Values between -1 and 1 are mapped to greyscale varying uniformly from black at -1 to white at 1 or vice-versa
Code for the current version
private void button1_Click(object sender, EventArgs e)
{
sw.Start();
LibNoise.Perlin perlinMap = new LibNoise.Perlin();
perlinMap.Lacunarity = lacunarity + 0.01d;
perlinMap.NoiseQuality = LibNoise.NoiseQuality.High;
perlinMap.OctaveCount = octaveCount;
perlinMap.Persistence = persistence;
perlinMap.Frequency = frequency;
perlinMap.Seed = 1024;
if (radioButton1.Checked)
perlinMap.NoiseQuality = LibNoise.NoiseQuality.Low;
else if (radioButton2.Checked)
perlinMap.NoiseQuality = LibNoise.NoiseQuality.Standard;
else if (radioButton3.Checked)
perlinMap.NoiseQuality = LibNoise.NoiseQuality.High;
double sample = trackBar6.Value * 10;
double[,] perlinArray = new double[resolutieX, resolutieY];
for (int x = 0; x < resolutieX; x++)
{
for (int y = 0; y < resolutieY; y++)
{
perlinArray[x, y] = perlinMap.GetValue(x / sample, y / sample, 1d);
}
}
draw(perlinArray);
textBox12.Text = sw.ElapsedMilliseconds.ToString() + "ms";
sw.Reset();
}
public void draw(double[,] array)
{
Color color = Color.DarkBlue;
// Bitmap b = new Bitmap(1, 1);
Color[,] colorArray = new Color[resolutieX, resolutieY];
Bitmap afbeelding = new Bitmap( 1024, 1024);
// int tileSize = 1024 / resolutieY;
for (int y = 1; y < resolutieY; y++)
{
for (int x = 1; x < resolutieX; x++)
{
colorArray[x, y] = array[x, y] <= 0.0 ? Color.DarkBlue :
array[x, y] <= 0.1 ? Color.Blue :
array[x, y] <= 0.2 ? Color.Beige :
array[x, y] <= 0.22 ? Color.LightGreen :
array[x, y] <= 0.40 ? Color.Green :
array[x, y] <= 0.75 ? Color.DarkGreen :
array[x, y] <= 0.8 ? Color.LightSlateGray :
array[x, y] <= 0.9 ? Color.Gray :
array[x, y] <= 1.0 ? Color.DarkSlateGray :
Color.DarkSlateGray;
// colorArray[]
// afbeelding.SetPixel(x, y, color);
}
}
for (int y = 1; y < resolutieY; y++)
{
for (int x = 1; x < resolutieX; x++)
{
afbeelding.SetPixel(x, y, colorArray[x, y]);
}
}
pictureBox1.Image = afbeelding;
}
Ohhh, lovely fractals... :)
As you are using a 2d vector from -1 to 1, you have to recalculate it to 0..255. Your function is
f(x) = 255 * (x+1)/2
Then all you have to do, is to create a 2D Color vector with f(x)
foreach (int value in 2dVector)
{
2dColorVector.add(new Color.fromArgb(255, f(x), f(x), f(x));
}
Is pseudocode, but i think you could understand it clearly :)
You can get a grayscale image by setting the primary colors (RGB) to equal values.
One way of achieving this is to make a function that calculates the average of the RGB components of the colors you have, and then set each of the components to the average value.
Example - Average method:
Color ToGrayscale(Color c)
{
int avg = (c.R + c.G + c.B)/3;
return Color.FromArgb(avg, avg, avg);
}
Then apply that function for each output pixel:
for (int y = 1; y < resolutieY; y++)
{
for (int x = 1; x < resolutieX; x++)
{
afbeelding.SetPixel(x, y, ToGrayscale(colorArray[x, y]));
}
}
Luminosity
A more sophisticated version of grayscaling is the Luminosity method. It also averages the values, but it is a weighted average that takes human perception into account.
The formula is: 0.2126*Red + 0.7152*Green + 0.0722*Blue.
You can see how the formula is weighted towards which colors the human eye is most sensitive to.
To see if this alternate approach looks better for your project you simply use the Luminosity formula for calculating the average instead:
Color ToGrayscaleLuminosity(Color c)
{
var avg = (int)Math.Round(0.2126 * c.R + 0.7152 * c.G + 0.0722 * c.B);
return Color.FromArgb(avg, avg, avg);
}

Categories