Ordered Dithering - Color Values Per Channel - c#

While moving forward with my algorithm for Ordered Dithering I got a problem, mainly I don't really know what col[levels] might be.
Here is the pseudocode
k - number of color values per channel
n - size of the threshold Bayers Matrix
My code which works somehow fine for K = 2, but it doesn't return correct result image when K = 3, K = 4 and so on
UPDATED CODE
class OrderedDithering
{
private float[,] bayerMatrix;
private float[,] dither2x2Matrix =
new float[,] { { 1, 3 },
{ 4, 2 } };
private float[,] dither3x3Matrix =
new float[,] { { 3, 7, 4 },
{ 6, 1, 9 },
{ 2, 8, 5 } };
public BitmapImage OrderedDitheringApply(BitmapImage FilteredImage, int valuesPerChannel, int thresholdSize)
{
Bitmap bitmap = ImageConverters.BitmapImage2Bitmap(FilteredImage);
if (thresholdSize == 2)
{
bayerMatrix = new float[2, 2];
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
bayerMatrix[i,j] = dither2x2Matrix[i,j] / 5;
}
else
{
bayerMatrix = new float[3, 3];
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
bayerMatrix[i, j] = dither3x3Matrix[i, j] / 10;
}
for (int i = 0; i < bitmap.Width; ++i)
for(int j = 0; j < bitmap.Height; ++j)
{
Color color = bitmap.GetPixel(i, j);
double r = Scale(0, 255, 0, 1, color.R);
double g = Scale(0, 255, 0, 1, color.G);
double b = Scale(0, 255, 0, 1, color.B);
int counter = 0;
counter += Dither(valuesPerChannel, r, thresholdSize, i, j);
counter += Dither(valuesPerChannel, g, thresholdSize, i, j);
counter += Dither(valuesPerChannel, b, thresholdSize, i, j);
if (counter == 0)
bitmap.SetPixel(i, j, Color.FromArgb(0,0,0));
else
bitmap.SetPixel(i, j, Color.FromArgb(255/counter, 255/counter, 255/counter));
}
return ImageConverters.Bitmap2BitmapImage(bitmap);
}
public int Dither(int valuesPerChannel, double colorIntensity, int thresholdSize, int i, int j)
{
double tempValue = (double)(Math.Floor((double)((valuesPerChannel - 1) * colorIntensity)));
double re = (valuesPerChannel - 1) * colorIntensity - tempValue;
if (re >= bayerMatrix[i % thresholdSize, j % thresholdSize])
return 1;
else
return 0;
}
public double Scale(double a0, double a1, double b0, double b1, double a)
{
return b0 + (b1 - b0) * ((a - a0) / (a1 - a0));
}
}

If you just need a dithering library that works with System.Drawing and supports ordered dithering feel free to use mine. It has an easily usable OrderedDitherer class.
But if you are just playing for the sake of curiosity, and would like to improve your algorithm, here are some comments:
You now always set the pixels black or white (btw, you can use just Color.Black instead of FromArgb(0, 0, 0), for example), so it cannot work for more colors
It is unclear from the provided code whether a target palette belongs to colorsNum but basically you need to quantize all dithered pixels to the nearest transformed color.
So instead of working by brightness you should apply the ordered matrix for each color channel of each pixels (between the 0..255 range), and pick a color from the target palette for the result. The 'nearest color' can have more interpretation but generally an euclidean search will do it.
Try to avoid Bitmap.SetPixel/GetPixel as they are terribly slow and SetPixel does not even work with bitmaps that have indexed palette PixelFormat.
Your code does not show the values of your matrix but the values should also be calibrated for the palette you use. The typical default values are good for a BW palette but they are probably too strong for a 256 color palette (the dithering "jumps over" more shades and introduces rather just noise than nice gradients). See this page for more info.
Feel free to explore the linked code base. The Dither extension method is the starting point for dithering a Bitmap in-place, and here are the OrderedDitherer constructor, the strength calibration for the min/max values of the matrix and a fairly fast nearest color search either by RGB channels or by brightness.

Related

Imager Sharpening Kernel producing odd result C#

I'm making a small app, where you can sharpen or blur an image in C#. So far blur is working flawlessly with any kernels of all sizes. However sharpening seems to cause this weird noisy/static image (something you'd see on a TV with no signal > see below). I've recoded this multiple times, and this time I tried to copy a solution from python, in case I keep messing it up somehow. Here's what I have for sharpening:
Color[,] clone = ud.CurrentSelected._bitmap; //gets the current image as a matrix
int[,] kernel = {{0, -1, 0}, {-1, 5, -1}, {0, -1, 0}};
int offset = 1;
int size = 100; //Image is 100x100 atm
for (int x = 0; x < size - offset; x++) {
for (int y = 0; y < size - offset; y++) {
NonDisplayedColour acc = Color.Black; //custom struct for storing and casting to regular Color without bounds -> not for displaying
for (int A = 0; A < 3; A++) {
for (int B = 0; B < 3; B++) {
int deltaX = x + A - offset;
int deltaY = y + B - offset;
NonDisplayedColour pixel = ud.CurrentSelected._bitmap[deltaX, deltaY];
int r = pixel.R * kernel[A, B];
int g = pixel.G * kernel[A, B];
int b = pixel.B * kernel[A, B];
acc.R += r;
acc.G += g;
acc.B += b;
}
}
clone[x,y] = acc;
}
}
ud.CurrentSelected._bitmap = clone;
This is just the calculation part, what displays the image is this:
Bitmap b = new Bitmap(ud.CurrentSelected._bitmap.Width, ud.CurrentSelected._bitmap.Height);
for (int x = 0; x < b.Width; ++x) {
for (int y = 0; y < b.Height; ++y) {
b.SetPixel(x, y, ud.CurrentSelected._bitmap[x, y]);
}
}
The NonDisplayedColour struct is just this, if anyone wants to know:
public struct NonDisplayedColour {
public NonDisplayedColour(int r, int g, int b) {
R = r;
G = g;
B = b;
A = 255;
}
public int A;
public int R;
public int G;
public int B;
public static implicit operator Color(NonDisplayedColour c) {
return Color.FromArgb((byte) c.A, (byte) c.R, (byte) c.G, (byte) c.B);
}
public static implicit operator NonDisplayedColour(Color c) {
return new NonDisplayedColour(c.R, c.G, c.B) {A = c.A};
}
}
The end result, is the following image.
Thanks for the help in advance.
PS.: I know locking bits would be much faster, but I'm going for simplicity rather than speed and SetPixel (to me at least) is much simpler.

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 vertically flip a bitmap in a byte array

I am writing a class for printing bitmaps to a portable bluetooth printer in Android via Mono For Android. My class is used to obtain the pixel data from the stream so that is can be sent to the printer in the correct format. Right now the class is simple, it just reads the height, width, and bits per pixel.
Using the offset it reads and returns the pixel data to the printer. Right now I am just working with 1 bit per pixel black and white images. The bitmaps I am working with are in Windows format.
Here is the original image:
Here is the result of printing, the first image is without any transformation. And the second one is the result of modifying the BitArray with the following code:
BitArray bits = new BitArray(returnBytes);
BitArray flippedBits = new BitArray(bits);
for (int i = 0, j = bits.Length - 1; i < bits.Length; i++, j--)
{
flippedBits[i] = bits[j];
}
My Question is:
How do I flip the image vertically when I am working with a byte array. I am having trouble finding the algorithm for doing this, all examples seem to suggest using established graphics libraries which I cannot use.
Edit:
My Bitmap is saved in a 1 dimensional array, with the first rows bytes, then the second, third, etc.
You need to do something like this:
BitArray bits = new BitArray(returnBytes);
BitArray flippedBits = new BitArray(bits);
for (int i = 0; i < bits.Length; i += width) {
for (int j = 0, k = width - 1; j < width; ++j, --k) {
flippedBits[i + j] = bits[i + k];
}
}
If you need to mirror picture upside-down, use this code:
BitArray bits = new BitArray(returnBytes);
BitArray flippedBits = new BitArray(bits);
for (int i = 0, j = bits.Length - width; i < bits.Length; i += width, j -= width) {
for (int k = 0; k < width; ++k) {
flippedBits[i + k] = bits[j + k];
}
}
For the format with width*height bits in row order, you just need to view the bit array as a two-dimensional array.
for(int row = 0; row < height; ++row) {
for(int column = 0; column < width; ++column) {
flippedBits[row*width + column] = bits[row*width + (width-1 - column)];
}
}
It would be a bit more complicated if there were more than one bit per pixel.
You need to use two loops, the first to iterate over all the rows and the second to iterate the pixels inside each row.
for (int y = 0; y < height; y++)
{
int row_start = (width/8) * y;
int flipped_row = (width/8) * (height-1 - y);
for (int x = 0; x < width/8; x++)
{
flippedBits[flipped_row+x] = bits[row_start+x];
}
}

How to resize multidimensional (2D) array in C#?

I tried the following but it just returns a screwed up array.
T[,] ResizeArray<T>(T[,] original, int rows, int cols)
{
var newArray = new T[rows,cols];
Array.Copy(original, newArray, original.Length);
return newArray;
}
Most methods in the array class only work with one-dimensional arrays, so you have to perform the copy manually:
T[,] ResizeArray<T>(T[,] original, int rows, int cols)
{
var newArray = new T[rows,cols];
int minRows = Math.Min(rows, original.GetLength(0));
int minCols = Math.Min(cols, original.GetLength(1));
for(int i = 0; i < minRows; i++)
for(int j = 0; j < minCols; j++)
newArray[i, j] = original[i, j];
return newArray;
}
To understand why it doesn't work with Array.Copy, you need to consider the layout of a multidimensional array in memory. The array items are not really stored as a bidimensional array, they're stored contiguously, row after row. So this array:
{ { 1, 2, 3 },
{ 4, 5, 6 } }
Is actually arranged in memory like that: { 1, 2, 3, 4, 5, 6 }
Now, assume you want to add one more row and one more column, so that the array looks like this:
{ { 1, 2, 3, 0 },
{ 4, 5, 6, 0 },
{ 0, 0, 0, 0 } }
The layout in memory would now be as follows: { 1, 2, 3, 0, 4, 5, 6, 0, 0, 0, 0, 0 }
But Array.Copy treats all arrays as one-dimensional. MSDN says:
When copying between multidimensional arrays, the array behaves like a long one-dimensional array, where the rows (or columns) are conceptually laid end to end
So when you try to copy the original array to the new one, it just copies one memory location to the other, which gives, in one-dimensional representation:
{ 1, 2, 3, 4, 5, 6, 0, 0, 0, 0, 0, 0 }.
If you convert that to a two-dimensional representation, you get the following:
{ { 1, 2, 3, 4 },
{ 5, 6, 0, 0 },
{ 0, 0, 0, 0 } }
This is why you're getting a screwed up array... Note that it would work property if you changed the number of rows, but not the number of columns.
This combines Thomas and Manuel's answers and provides the performance benefit of Array.Copy and the ability to both increase and decrease the size of the array.
protected T[,] ResizeArray<T>(T[,] original, int x, int y)
{
T[,] newArray = new T[x, y];
int minX = Math.Min(original.GetLength(0), newArray.GetLength(0));
int minY = Math.Min(original.GetLength(1), newArray.GetLength(1));
for (int i = 0; i < minY; ++i)
Array.Copy(original, i * original.GetLength(0), newArray, i * newArray.GetLength(0), minX);
return newArray;
}
Please note that the x and y axis of your array is up to your own implementation and you may need to switch the 0s and 1s around to achieve the desired effect.
Thank you Thomas, your explanation was very helpful but your implemented solution is too slow. I modified it to put Array.Copy to good use.
void ResizeArray<T>(ref T[,] original, int newCoNum, int newRoNum)
{
var newArray = new T[newCoNum,newRoNum];
int columnCount = original.GetLength(1);
int columnCount2 = newRoNum;
int columns = original.GetUpperBound(0);
for (int co = 0; co <= columns; co++)
Array.Copy(original, co * columnCount, newArray, co * columnCount2, columnCount);
original = newArray;
}
Here I'm assuming that there are more rows than columns so I structured the array as [columns, rows]. That way I use Array.Copy on an entire column in one shot (much faster than one cell a time).
It only works to increment the size of the array but it can probably be tweaked to reduce the size too.
And for generic resizing of multi dimensional arrays:
public static class ArrayExtentions {
public static Array ResizeArray(this Array arr, int[] newSizes) {
if (newSizes.Length != arr.Rank) {
throw new ArgumentException("arr must have the same number of dimensions as there are elements in newSizes", "newSizes");
}
var temp = Array.CreateInstance(arr.GetType().GetElementType(), newSizes);
var sizesToCopy = new int[newSizes.Length];
for (var i = 0; i < sizesToCopy.Length; i++) {
sizesToCopy[i] = Math.Min(newSizes[i], arr.GetLength(i));
}
var currentPositions = new int[sizesToCopy.Length];
CopyArray(arr, temp, sizesToCopy, currentPositions, 0);
return temp;
}
private static void CopyArray(Array arr, Array temp, int[] sizesToCopy, int[] currentPositions, int dimmension) {
if (arr.Rank - 1 == dimmension) {
//Copy this Array
for (var i = 0; i < sizesToCopy[dimmension]; i++) {
currentPositions[dimmension] = i;
temp.SetValue(arr.GetValue(currentPositions), currentPositions);
}
} else {
//Recursion one dimmension higher
for (var i = 0; i < sizesToCopy[dimmension]; i++) {
currentPositions[dimmension] = i;
CopyArray(arr, temp, sizesToCopy, currentPositions, dimmension + 1);
}
}
}
}
I was looking for something like this, but something that would effectively let me "pad" a 2D array from both ends, and also have the ability to reduce it.
I've run a very simple test:
The array was string[1000,1000], average time for my machine was 44ms per resize.
The resize increased or decreased padding on all sides by 1 each time, so all data in the array was copied. This performance hit was more than acceptable for my requirements.
public static void ResizeArray<T>(
ref T[,] array, int padLeft, int padRight, int padTop, int padBottom)
{
int ow = array.GetLength(0);
int oh = array.GetLength(1);
int nw = ow + padLeft + padRight;
int nh = oh + padTop + padBottom;
int x0 = padLeft;
int y0 = padTop;
int x1 = x0 + ow - 1;
int y1 = y0 + oh - 1;
int u0 = -x0;
int v0 = -y0;
if (x0 < 0) x0 = 0;
if (y0 < 0) y0 = 0;
if (x1 >= nw) x1 = nw - 1;
if (y1 >= nh) y1 = nh - 1;
T[,] nArr = new T[nw, nh];
for (int y = y0; y <= y1; y++)
{
for (int x = x0; x <= x1; x++)
{
nArr[x, y] = array[u0 + x, v0 + y];
}
}
array = nArr;
}
padLeft, padRight, padTop, padBottom can be negative or positive. If you pass in all 0s, the array generated will be identical to the source array.
This could be particularly useful for anyone who wants to "scroll" their elements around their array.
Hope it's of use to someone!
This builds on Manuel's answer to also allow to apply an offset to the copied data (e.g. to copy the source array to the center of the target array, instead of to [0, 0]):
public static T[,] ResizeArray<T>(T[,] original, int newWidth, int newHeight, int offsetX = 0, int offsetY = 0)
{
T[,] newArray = new T[newWidth, newHeight];
int width = original.GetLength(0);
int height = original.GetLength(1);
for (int x = 0; x < width; x++) {
Array.Copy(original, x * height, newArray, (x + offsetX) * newHeight + offsetY, height);
}
return newArray;
}
I really like Stephen Tierney's answer building upon the work of others.
As Stephen notes the x/y is up to interpretation.
I have refactored it slightly to use m*n sizes & ij coordinate indexing that is probably the most common notation for matrices (wikipedia for reference https://en.wikipedia.org/wiki/Matrix_(mathematics)).
In this notation,
'm' is the number of rows
'n' is the number of columns
'i' is the first coordinate, aka row index (increases as you go down)
public static T[,] Resize2D<T>(this T[,] original, int m, int n)
{
T[,] newArray = new T[m, n];
int mMin = Math.Min(original.GetLength(0), newArray.GetLength(0));
int nMin = Math.Min(original.GetLength(1), newArray.GetLength(1));
for (int i = 0; i < mMin; i++)
Array.Copy(original, i * original.GetLength(1), newArray, i * newArray.GetLength(1), nMin);
return newArray;
}

C# predictive coding for image compression

I've been playing with Huffman Compression on images to reduce size while maintaining a lossless image, but I've also read that you can use predictive coding to further compress image data by reducing entropy.
From what I understand, in the lossless JPEG standard, each pixel is predicted as the weighted average of the adjacent 4 pixels already encountered in raster order (three above and one to the left). e.g., trying to predict the value of a pixel a based on preceding pixels, x, to the left as well as above a :
x x x
x a
Then calculate and encode the residual (difference between predicted and actual value).
But what I don't get is if the average 4 neighbor pixels aren't a multiple of 4, you'd get a fraction right? Should that fraction be ignored? If so, would the proper encoding of an 8 bit image (saved in a byte[]) be something like:
public static void Encode(byte[] buffer, int width, int height)
{
var tempBuff = new byte[buffer.Length];
for (int i = 0; i < buffer.Length; i++)
{
tempBuff[i] = buffer[i];
}
for (int i = 1; i < height; i++)
{
for (int j = 1; j < width - 1; j++)
{
int offsetUp = ((i - 1) * width) + (j - 1);
int offset = (i * width) + (j - 1);
int a = tempBuff[offsetUp];
int b = tempBuff[offsetUp + 1];
int c = tempBuff[offsetUp + 2];
int d = tempBuff[offset];
int pixel = tempBuff[offset + 1];
var ave = (a + b + c + d) / 4;
var val = (byte)(ave - pixel);
buffer[offset + 1] = val;
}
}
}
public static void Decode(byte[] buffer, int width, int height)
{
for (int i = 1; i < height; i++)
{
for (int j = 1; j < width - 1; j++)
{
int offsetUp = ((i - 1) * width) + (j - 1);
int offset = (i * width) + (j - 1);
int a = buffer[offsetUp];
int b = buffer[offsetUp + 1];
int c = buffer[offsetUp + 2];
int d = buffer[offset];
int pixel = buffer[offset + 1];
var ave = (a + b + c + d) / 4;
var val = (byte)(ave - pixel);
buffer[offset + 1] = val;
}
}
}
I don't see how this really will reduce entropy? How will this help compress my images further while still being lossless?
Thanks for any enlightenment
EDIT:
So after playing with the predictive coding images, I noticed that the histogram data shows a lot of +-1's of the varous pixels. This reduces entropy quite a bit in some cases. Here is a screenshot:
Yes, just truncate. Doesn't matter because you store the difference. It reduces entropy because you only store small values, a lot of them will be -1, 0 or 1. There are a couple of off-by-one bugs in your snippet btw.

Categories