How to 'normalize' a grayscale image? - c#

My math is a bit rusty. I'm trying to equalize a histogram of a 2D array which represents grayscale values in the range 0-255 (values may not be whole numbers because of how they are computed).
I found this article on Wikipedia, but I don't quite understand the formulas they present.
ni, n and L I can compute, but I'm not quite sure how to implement this cdf function. Might this function be of use?
Here's what I've got so far:
static double[,] Normalize(double[,] mat)
{
int width = mat.GetLength(0);
int height = mat.GetLength(1);
int nPixels = width*height;
double sum = 0;
double max = double.MinValue;
double min = double.MaxValue;
var grayLevels = new Dictionary<double, int>();
foreach (var g in mat)
{
sum += g;
if (g > max) max = g;
if (g < min) min = g;
if (!grayLevels.ContainsKey(g)) grayLevels[g] = 0;
++grayLevels[g];
}
double avg = sum/nPixels;
double range = max - min;
var I = new double[width,height];
// how to normalize?
return I;
}

Found something that you might find useful
http://sonabstudios.blogspot.in/2011/01/histogram-equalization-algorithm.html
Hope that helps

Calculating the cumulative distribution function involves a couple of steps.
First you get the frequency distribution of your grayscale values.
So something like:
freqDist = new int[256];
for each (var g in mat)
{
int grayscaleInt = (int)g;
freqDist[grayscaleInt]++;
}
Then to get your CDF, something like:
cdf = new int[256];
int total = 0;
for (int i = 0; i < 256; i++)
{
total += freqDist[i];
cdf[i] = total;
}

I can help you to understand your link,
first, counting value which represent image, shows in that link,
Value Count Value Count Value Count Value Count Value Count
52 1 64 2 72 1 85 2 113 1
55 3 65 3 73 2 87 1 122 1
58 2 66 2 75 1 88 1 126 1
59 3 67 1 76 1 90 1 144 1
60 1 68 5 77 1 94 1 154 1
61 4 69 3 78 1 104 2
62 1 70 4 79 2 106 1
63 2 71 2 83 1 109 1
it is means, the image is created with values above, nothing else.
second, sums the value cumulatively from 52 to 154
Value cdf Value cdf Value cdf Value cdf Value cdf
52 1 64 19 72 40 85 51 113 60
55 4 65 22 73 42 87 52 122 61
58 6 66 24 75 43 88 53 126 62
59 9 67 25 76 44 90 54 144 63
60 10 68 30 77 45 94 55 154 64
61 14 69 33 78 46 104 57
62 15 70 37 79 48 106 58
63 17 71 39 83 49 109 59
it is means,
value 52 have 1 cdf cause it is initial value,
value 55 have 4 cdf cause it has 3 count in image plus 1 cdf from 52,
value 58 have 6 cdf cause it has 2 count in image plus 4 cdf from 55,
and so on.. till..
value 154 have 64 cdf cause it has 1 count in image plus 63 cdf from 144.
then, calculating histogram equalization formula for each image values based on the function
cdf(v) is represent current cdf value from current image value,
in this case, if h(v) = 61 so cdf(v) = 14
cdfmin is represent initial cdf value, in this case, 1 cdf from value 52
happy coding.. ^^

Here's my implementation:
private static byte[,] Normalize(byte[,] mat)
{
int width = mat.GetLength(0);
int height = mat.GetLength(1);
int nPixels = width*height;
var freqDist = new int[256];
foreach (var g in mat)
{
++freqDist[g];
}
var cdf = new int[256];
int total = 0;
for (int i = 0; i < 256; ++i)
{
total += freqDist[i];
cdf[i] = total;
}
int cdfmin = 0;
for (int i = 0; i < 256; ++i)
{
if (cdf[i] > 0)
{
cdfmin = cdf[i];
break;
}
}
var I = new byte[width,height];
double div = (nPixels - cdfmin) / 255d;
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
I[x, y] = (byte)Math.Round((cdf[mat[x, y]] - cdfmin) / div);
}
}
return I;
}
I changed it from using doubles to bytes to work better with the histogram (freqDist).

In addition to what John says, you will need to use the cdf array to compute the new value for every pixel. You do this by:
Adjust John's second iteration to get the first i that has a
freqDist > 0 and call that i imin
Going pixel by pixel i,j between 0 and width and 0 and height repectively and
evaluating round((cdf[pixel[i,j]]-cdf[imin])/(width*height-cdf[imin]))*255),
that is the normalized pixel value at that location.

You can use this function I just wrote:
public static Bitmap ContrastStretch(Bitmap srcImage, double blackPointPercent = 0.02, double whitePointPercent = 0.01)
{
BitmapData srcData = srcImage.LockBits(new Rectangle(0, 0, srcImage.Width, srcImage.Height), ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
Bitmap destImage = new Bitmap(srcImage.Width, srcImage.Height);
BitmapData destData = destImage.LockBits(new Rectangle(0, 0, destImage.Width, destImage.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
int stride = srcData.Stride;
IntPtr srcScan0 = srcData.Scan0;
IntPtr destScan0 = destData.Scan0;
var freq = new int[256];
unsafe
{
byte* src = (byte*) srcScan0;
for (int y = 0; y < srcImage.Height; ++y)
{
for (int x = 0; x < srcImage.Width; ++x)
{
++freq[src[y*stride + x*4]];
}
}
int numPixels = srcImage.Width*srcImage.Height;
int minI = 0;
var blackPixels = numPixels*blackPointPercent;
int accum = 0;
while (minI < 255)
{
accum += freq[minI];
if (accum > blackPixels) break;
++minI;
}
int maxI = 255;
var whitePixels = numPixels*whitePointPercent;
accum = 0;
while (maxI > 0)
{
accum += freq[maxI];
if (accum > whitePixels) break;
--maxI;
}
double spread = 255d/(maxI - minI);
byte* dst = (byte*) destScan0;
for (int y = 0; y < srcImage.Height; ++y)
{
for (int x = 0; x < srcImage.Width; ++x)
{
int i = y*stride + x*4;
byte val = (byte) Clamp(Math.Round((src[i] - minI)*spread), 0, 255);
dst[i] = val;
dst[i + 1] = val;
dst[i + 2] = val;
dst[i + 3] = 255;
}
}
}
srcImage.UnlockBits(srcData);
destImage.UnlockBits(destData);
return destImage;
}
static double Clamp(double val, double min, double max)
{
return Math.Min(Math.Max(val, min), max);
}
The defaults mean that the darkest 2% of pixels will become black, the lightest 1% will become white, and everything in between will be stretched to fill the color space. This is the same as the default for ImageMagick.
This algorithm has the fun side effect that if you use values above 50% then it will invert the image! Set to .5, .5 to get a black & white image (2 shades) or 1, 1 to get a perfect inversion.
Assumes your image is already grayscale.

Related

Get the pre-last element of a string split by spaces

Input examples:
7 9 12 16 18 21 25 27 30 34 36 39 43 45 48 52 54 57 61
7 9 12 16 18 21 25 27 30 34 36 39 43 45 48 52 54 57 ... 75 79
Note that it ends with a space.
I want to get 57 in the first case and 75 in the second case as integer. I tried with the following:
Convert.ToInt32(Shorten(sequence).Split(' ').ElementAt(sequence.Length - 2));
The problem is that sequence.Length is not really the right index.
You can use the overload for Split() and pass the RemoveEmptyEntires enum:
string input = "7 9 12 16 18 21 25 27 30 34 36 39 43 45 48 52 54 57 61 ";
var splitInput = input.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
var inputInt = Convert.ToInt32(splitInput[splitInput.Length - 2]);
// inputInt is 57
Doing it this way allows your last element to actually be what you want.
Fiddle here
Based on maccettura's answer, in C# 8 you can simplify index acces like so
var input = "1 2 3";
var parts = input.Split(' ', StringSplitOptions.RemoveEmptyEntries);
var value = parts.Length >= 2 ? Convert.ToInt32(parts[^2]) : null;
How about something that doesn't use strings at all.
public static int? SplitReverseInt(this string str, int ixFromBack)
{
var inWord = false;
var wEnd = 0;
var found = 0;
for (int i = str.Length - 1; i >= 0; i--)
{
var charr = str[i];
if (char.IsWhiteSpace(charr))
{
// we found the beginning of a word
if (inWord)
{
if (found == ixFromBack)
{
var myInt = 0;
for (int j = i+1; j <= wEnd; j++)
myInt = (myInt * 10 + str[j] - '0');
return myInt;
}
inWord = false;
found++;
}
}
else
{
if (!inWord)
{
wEnd = i;
inWord = true;
}
}
}
// word (number) is at the beginning of the string
if (inWord && found == ixFromBack)
{
var myInt = 0;
for (int j = 0; j <= wEnd; j++)
myInt = (myInt * 10 + str[j] - '0');
return myInt;
}
return null;
}
Performance is about 10 times faster on the example strings.
This only loops from the back, and only fetches one number, it doesnt create substrings or an array of strings we don't need.
Use like this:
var numberFromBack = SplitReverseInt(input, 1);

Calculate sum of numbers on matrix diagonal

I have a dynamic matrix and I need to to calculate sum of digits in this way:
0 1 2 3 4 5 6
10 11 12 13 14 15 16
20 21 22 23 24 25 26
30 31 32 33 34 35 36
40 41 42 43 44 45 46
50 51 52 53 54 55 56
60 61 62 63 64 65 66
I can't understand in which way I should compare i and j:
long result = 0;
for (int i = 0; i < len; i++)
{
for (int j = 0; j < len; j++)
{
// only works for diagonal
if (i == j) // should use j - 1 or i - 1?
{
result += matrix[i][j];
}
}
}
no need to scan full matrix:
long result = 0;
for (int i = 0; i < len; i++)
{
result += matrix[i][i]; // diagonal
if (i < len - 1) // stay within array bounds
result += matrix[i][i+1]; // next to diagonal
}
modification without index check on every iteration:
// assign corner value from bottom row to result
long result = matrix[len-1][len-1];
// for each row (except last!) add diagonal and next to diagonal values
for (int i = 0; i < len-1; i++)
result += matrix[i][i] + matrix[i][i+1];

array numbers which sum is dividing on 4

I want to print numbers on label from 1-to 100
The number's sum must be dividing on 4.
Example:
print 35. because 3+5 = 8 .
8 dividing on 4.
This is code
from loop printing numbers. but how choose those numbers?
print those numbers from 1 to 100 ;
for (int i = 1; i < 100; i++)
{
//select numbers wich sum is dividing on 4
label3.Text += Convert.ToString(i) + " | ";
}
Stolen from Greg Hewgill answer's, you can use his algorithm and use remainder operator (%) like;
int sum, temp;
for (int i = 1; i < 100; i++)
{
sum = 0;
temp = i;
while (temp != 0)
{
sum += temp % 10;
temp /= 10;
}
if (sum % 4 == 0)
{
Console.WriteLine(i);
}
}
Result will be;
4
8
13
17
22
26
31
35
39
40
44
48
53
57
62
66
71
75
79
80
84
88
93
97
Here a demonstration.
You should use a nested loop for that , and use the % operator (% means the rest of division):
for (int i = 1; i < 100; i++)
{
for (int j = i; j < 100; j++)
{
//select numbers wich sum is dividing on 4
if( (i+j)%4 == 0)
{
label3.Text += Convert.ToString(i) + Convert.ToString(j) " | ";
}
}
}

Converting single dimension array to a 2D array in C# for AES data matrix

I'm trying to make a 2D array from a single dimension array to make a data state in Rijndael or AES cryptographical process. I've been trying using this code here;
public byte[,] MakeAState(byte[] block){
byte[,] State;
foreach (byte i in block)
for (int row = 0; row < 4; row++)
for (int column = 0; column < 4; column++)
State[column, row] = i;
return State;
}
and I intend to make the result to be like this
//Original Sequence
[99 111 98 97 112 97 115 115 99 111 98 97 112 97 115 115]
//Desired Sequence
[99 112 99 112]
[111 97 111 97]
[98 115 98 115]
[97 115 97 115]
The results always comes out as if the elements of Block used as if the index of the State array, causing an 'out-of boundary' error message appearing. any idea on how to manage this?
This should be what you want, and it's working with division and modulo to determine column and row(just switch "i % 4" with "i / 4" if you want to turn the matrix):
class Program
{
static void Main(string[] args)
{
byte[] original = new byte[] { 99, 111, 98, 97, 112, 97, 115, 115, 99, 111, 98, 97, 112, 97, 115, 115 };
byte[,] result = MakeAState(original);
for (int row = 0; row < 4; row++)
{
for (int column = 0; column < 4; column++)
{
Console.Write(result[row,column] + " ");
}
Console.WriteLine();
}
}
public static byte[,] MakeAState(byte[] block)
{
if (block.Length < 16)
{
return null;
}
byte[,] state = new byte[4,4];
for (int i = 0; i < 16; i++)
{
state[i % 4, i / 4] = block[i];
}
return state;
}
}
}
Output:
99 112 99 112
111 97 111 97
98 115 98 115
97 115 97 115
You likely flipped row and column on State[column, row] = i; which might be what's causing your out of bounds exception. Can't tell without more information about your variables, though.
But that's not the only issue here. Assuming you just want the array to be split into groups of four. This is your current situation if you flip row/columnand get past your exception.
//Original sequence:
[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
//Desired sequence:
[0 4 8 12]
[1 5 9 13]
[3 6 10 14]
[4 7 11 15]
//What you are currently getting:
[15 15 15 15]
[15 15 15 15]
[15 15 15 15] //<-- Last value of original sequence, everywhere.
What's happening in your code is every position in Block is placed in every position in the new array, which means that you'll end up with an array filled with the last value of Block when the algorithm is finished.
Changing it to something like this would return the result you want.
public static byte[,] State(byte[] Block)
{
if (Block.Length % 16 != 0)
throw new Exception("Byte array length must be divisible by 16.");
var rowCount = Block.Length / 4;
var State = new byte[rowCount, 4];
for (int column = 0, block = 0; column < 4; column++)
for (int row = 0; row < rowCount; row++, block++)
State[row, column] = Block[block];
return State;
}

Mathematically navigating a large 2D Numeric grid in C#

I am trying to find certain coordinates of interest within a very large virtual grid. This grid does not actually exist in memory since the dimensions are huge. For the sake of this question, let's assume those dimensions to be (Width x Height) = (Int32.MaxValue x Int32.MaxValue).
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100
Known data about grid:
Dimensions of the grid = (Int32.MaxValue x Int32.MaxValue).
Value at any given (x, y) coordinate = Product of X and Y = (x * y).
Given the above large set of finite numbers, I need to calculate a set of coordinates whose value (x * y) is a power of e. Let's say e is 2 in this case.
Since looping through the grid is not an option, I thought about looping through:
int n = 0;
long r = 0;
List<long> powers = new List<long>();
while (r < (Int32.MaxValue * Int32.MaxValue))
{
r = Math.Pow(e, n++);
powers.Add(r);
}
This gives us a unique set of powers. I now need to find out at what coordinates each power exists. Let's take 2^3=8. As shown in the grid above, 8 exists in 4 coordinates: (8,1), (4,2), (2,4) & (1, 8).
Clearly the problem here is finding multiple factors of the number 8 but this would become impractical for larger numbers. Is there another way to achieve this and am I missing something?
Using sets won't work since the factors don't exist in memory.
Is there a creative way to factor knowing that the number in question will always be a power of e?
The best method is to factor e into it prime components. Lets say they are as follows: {a^m, b^p, c^q}. Then you build set for each power of e, for example if m=2, p=1, q=3,
e^1 = {a, a, b, c, c, c}
e^2 = (a, a, a, a, b, b, c, c, c, c, c, c}
etc. up to e^K > Int32.MaxValue * Int32.MaxValue
then for each set you need to iterate over each unique subset of these sets to form one coordinate. The other coordinate is what remains. You will need one nested loop for each of the unique primes in e. For example:
Lets say for e^2
M=m*m;
P=p*p;
Q=q*q;
c1 = 1 ;
for (i=0 ; i<=M ; i++)
{
t1 = c1 ;
for (j=0 ; j<=P ; j++)
{
t2 = c1 ;
for (k=0 ; k<=Q ; k++)
{
// c1 holds first coordinate
c2 = e*e/c1 ;
// store c1, c2
c1 *= c ;
}
c1 = t2*b ;
}
c1 = t1*a ;
}
There should be (M+1)(P+1)(Q+1) unique coordinates.
Another solution, not as sophisticated as the idea from Commodore63, but therefore maybe a little bit simpler (no need to do a prime factorization and calculating all proper subsets):
const int MaxX = 50;
const int MaxY = 50;
const int b = 6;
var maxExponent = (int)Math.Log((long)MaxX * MaxY, b);
var result = new List<Tuple<int, int>>[maxExponent + 1];
for (var i = 0; i < result.Length; ++i)
result[i] = new List<Tuple<int, int>>();
// Add the trivial case
result[0].Add(Tuple.Create(1, 1));
// Add all (x,y) with x*y = b
for (var factor = 1; factor <= (int)Math.Sqrt(b); ++factor)
if (b % factor == 0)
result[1].Add(Tuple.Create(factor, b / factor));
// Now handle the rest, meaning x > b, y <= x, x != 1, y != 1
for (var x = b; x <= MaxX; ++x) {
if (x % b != 0)
continue;
// Get the max exponent for b in x and the remaining factor
int exp = 1;
int lastFactor = x / b;
while (lastFactor >= b && lastFactor % b == 0) {
++exp;
lastFactor = lastFactor / b;
}
if (lastFactor > 1) {
// Find 1 < y < b with x*y yielding a power of b
for (var y = 2; y < b; ++y)
if (lastFactor * y == b)
result[exp + 1].Add(Tuple.Create(x, y));
} else {
// lastFactor == 1 meaning that x is a power of b
// that means that y has to be a power of b (with y <= x)
for (var k = 1; k <= exp; ++k)
result[exp + k].Add(Tuple.Create(x, (int)Math.Pow(b, k)));
}
}
// Output the result
for (var i = 0; i < result.Length; ++i) {
Console.WriteLine("Exponent {0} - Power {1}:", i, Math.Pow(b, i));
foreach (var pair in result[i]) {
Console.WriteLine(" {0}", pair);
//if (pair.Item1 != pair.Item2)
// Console.WriteLine(" ({0}, {1})", pair.Item2, pair.Item1);
}
}

Categories

Resources