Generate a random array of integers in a loop in C - c

I was trying to generate a random array of integers of length 16 inside a loop. The elements of the array will lie inside [0, 255]. I thought assigning random integers from [0, 255] would suffice; but it does not work (one random array is created which remains unchanged over iterations). Then I tried shuffling, but the situation does not improve (I also notice that the probability of 0 in the 'random' array is significantly larger).
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//#define Shuffle
/* Generate a random integer array of length `size` with elements from [0, 255] */
int* random_sample(int size)
{
int i, j, k;
int *elements = malloc(size*sizeof(int));
/* Assign random integers */
for (i = size - 1; i > 0; --i)
{
elements[i] = rand() % 256;
}
/* Shuffle */
#ifdef Shuffle
for (i = size - 1; i > 0; --i) {
j = rand() % size;
k = elements[i];
elements[i] = elements[j];
elements[j] = k;
}
#endif
return elements;
}
int main(int argc, char const *argv[])
{
int LENGTH = 16, i, iteration;
int *random_array = random_sample(LENGTH);
srand(time(NULL));
for (iteration = 0; iteration < 10; ++iteration)
{
for (i = 0; i < LENGTH; ++i)
printf("%d, ", random_array[i]);
puts("");
}
return 0;
}
A typical output looks like:
0, 227, 251, 242, 171, 186, 205, 41, 236, 74, 255, 81, 115, 105, 198, 103,
0, 227, 251, 242, 171, 186, 205, 41, 236, 74, 255, 81, 115, 105, 198, 103,
0, 227, 251, 242, 171, 186, 205, 41, 236, 74, 255, 81, 115, 105, 198, 103,
0, 227, 251, 242, 171, 186, 205, 41, 236, 74, 255, 81, 115, 105, 198, 103,
0, 227, 251, 242, 171, 186, 205, 41, 236, 74, 255, 81, 115, 105, 198, 103,
0, 227, 251, 242, 171, 186, 205, 41, 236, 74, 255, 81, 115, 105, 198, 103,
0, 227, 251, 242, 171, 186, 205, 41, 236, 74, 255, 81, 115, 105, 198, 103,
0, 227, 251, 242, 171, 186, 205, 41, 236, 74, 255, 81, 115, 105, 198, 103,
0, 227, 251, 242, 171, 186, 205, 41, 236, 74, 255, 81, 115, 105, 198, 103,
0, 227, 251, 242, 171, 186, 205, 41, 236, 74, 255, 81, 115, 105, 198, 103,
I tried several variations of the above code, but none of them works. Need help!
EDIT
I was trying variations of the code, and mistakenly printed the same unchanged array (as pointed out by some others - thanks to them); originally I wrote
int main(int argc, char const *argv[])
{
int LENGTH = 16, i, iteration;
int *random_array;
srand(time(NULL));
for (iteration = 0; iteration < 10; ++iteration)
{
random_array = random_sample(LENGTH);
for (i = 0; i < LENGTH; ++i)
printf("%d, ", random_array[i]);
puts("");
}
return 0;
}
which print much more 0s.
EDIT (2)
Thanks to #pmg, I found the problem. Inside random_sample function, changing the first
for (i = size - 1; i > 0; --i) to for (i = size - 1; i >= 0; --i) works fine!
Thank you all.

Try the code below. For the array to contain different (random) values at every iteration, you need to put different values in it :)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//#define Shuffle
/* Generate a random integer array of length `size` with elements from [0, 255] */
int* random_sample(int size)
{
int i, j, k;
int *elements = malloc(size*sizeof(int));
/* Assign random integers */
for (i = size - 1; i > 0; --i)
{
elements[i] = rand() % 256;
}
/* Shuffle */
#ifdef Shuffle
for (i = size - 1; i > 0; --i) {
j = rand() % size;
k = elements[i];
elements[i] = elements[j];
elements[j] = k;
}
#endif
return elements;
}
int main(int argc, char const *argv[])
{
int LENGTH = 16, i, iteration;
int *random_array;
srand(time(NULL));
for (iteration = 0; iteration < 10; ++iteration)
{
random_array = random_sample(LENGTH);
for (i = 0; i < LENGTH; ++i)
printf("%d, ", random_array[i]);
puts("");
free(random_array);
}
return 0;
}

Here's some comments on your code to clarify the problem.
int main(int argc, char const *argv[])
{
int LENGTH = 16, i, iteration;
int *random_array = random_sample(LENGTH); // ARRAY is created and filled in here.
srand(time(NULL)); // Random generator is initialized here.
// WAIT WHAT? You already filled in the array above!
// It is too late now to initialize the Generator!

In addition to what others have said above, I think its important to note the following on the rand function as written in the man page:
Note:
The versions of rand() and srand() in the Linux C Library use the same random number generator as random(3) and srandom(3), so the lower-order bits should be as random as the higher-order bits. However, on older rand() implementations, and on current implementations on different systems, the lower-order bits are much less random than the higher-order bits. Do not use this function in applications intended to be portable when good randomness is needed. (Use random(3) instead.)
There are two possible alternatives:
1) Use the random function as recommended by the note.
2) Use the higher-order bits of the random number as follows:
elements[i] = (rand() * 256) / RANDMAX;

Related

C qsort not sorting last item in multidimensional array

I am using the qsort function in C to sort 3 columns of integers. It sorts my 2D array fine, except for the last item.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#define ARRAYSIZE 10
int array[ARRAYSIZE][3];
static int x_then_z(const void *a, const void *b) {
const int *arr1 = (const int*)a;
const int *arr2 = (const int*)b;
int diff1 = arr1[0] - arr2[0]; //x
if(diff1) return diff1;
return arr1[2] - arr2[2]; //z
}
static int z_then_x(const void *a, const void *b) {
const int *arr1 = (const int*)a;
const int *arr2 = (const int*)b;
int diff1 = arr1[2] - arr2[2]; //z
if(diff1) return diff1;
return arr1[0] - arr2[0]; //x
}
void print_array() {
for(int i = 0; i < ARRAYSIZE; i++){
printf("%d, %d, %d\n", array[i][0], array[i][1], array[i][2]);
}
}
int main(int argc, char *argv[]){
fill_array();
//print_array();
//printf("\n");
qsort(array, ARRAYSIZE, 3*sizeof(int), x_then_z);
fprintf(stderr, "Sorted by x then z\n");
print_array();
printf("\n");
qsort(array, ARRAYSIZE, 3*sizeof(int), z_then_x);
fprintf(stderr, "Sorted by z then x\n");
print_array();
return EXIT_SUCCESS;
}
I have named my columns x, y and z (so as not to confuse myself in the comparison functions where I have a and b). The fill_array function fills the array with the following computed input:
31, 56, 8
39, 71, 9
65, 76, 10
64, 129, 12
44, 191, 14
105, 199, 15
169, 319, 19
44, 321, 18
319, 364, 22
295, 551, 25
However, the output is this:
Sorted by x then z
31, 56, 8
39, 71, 9
44, 191, 14
44, 321, 18
64, 129, 12
65, 76, 10
105, 199, 15
169, 319, 19
319, 364, 22
**295, 551, 25**
Sorted by z then x
31, 56, 8
39, 71, 9
65, 76, 10
64, 129, 12
44, 191, 14
105, 199, 15
44, 321, 18
169, 319, 19
319, 364, 22
295, 551, 25
You can see that the last value of the array is not sorted. If I change ARRAYSIZE to a larger number, the last value in the array is not sorted. Where am I going wrong?
The fill_array function had an off by 1 error. When filling the array, it was starting at 1, not 0

I did not understand what is happening with int array in my code

#include <stdio.h>
int main()
{
int marks[40] = {83, 86, 97, 83, 93, 83, 86, 52, 49, 41, 42, 47, 90, 59, 63, 86, 40, 46, 92, 56, 51, 48, 67, 49, 42, 90, 42, 83, 47, 95, 69, 82, 82, 58, 69, 67, 53, 56, 71, 62};
int i,j,count[101],tm;
for(i=0;i<101;i++)
{
count[i]=0;
}
for(i=0;i<40;i++)
{
tm=marks[i];
count[tm]=count[tm]+1;
}
for(i=0;i<=100;i++)
{
if(count[i]!=0)
{
printf("Marks: %d count: %d\n",i,count[i]);
}
}
return 0;
}
This is my code. I did not understand in this here.
first i=0, marks[i], marks[0] means marks[0]=83
so
tm=marks[0]=83
and then
count[tm]=count[tm]+1;
And I did not understand in this line.
I added some comments to your code such that you can easier understand what is happening.
#include <stdio.h>
int main(void) // use void if your function has no parameters
{
int marks[] = {83, 86, 97, 83, 93, 83, 86, 52, 49, 41, 42, 47, 90, 59, 63, 86, 40, 46, 92, 56, 51, 48, 67, 49, 42, 90, 42, 83, 47, 95, 69, 82, 82, 58, 69, 67, 53, 56, 71, 62}; // you can leave out the array size if you instantiate it afterwards
int i, tm; // j is never used, so leave it out
int count[101]; // count[i] tells you in the end how often the mark i occured in the marks array
for(i=0; i < 101; i++) // initialize the count array with zeros
{
count[i]=0;
}
for(i=0;i<40;i++) // loop over the marks array and increment thhe count array at the current mark position by one
{
tm=marks[i];
count[tm]=count[tm]+1; // increment the count of mark i by one
}
// marks[i] tells you how often i appears in the marks array -> marks is a frequency table
for(i=0;i<=100;i++) // print out how often a mark appeared, but only if it appeared at least once
{
if(count[i]!=0)
{
printf("Marks: %d count: %d\n",i,count[i]);
}
}
return (0);
}
Those two lines
tm=marks[i];
count[tm]=count[tm]+1;
do the following:
get the value stored in marks[i]
store the value pulled in 1. into tm
get the value of count[tm]
add 1 to what had been pulled in 3.
store the result of the addition done in 4. into count[tm], overwriting the value that had been pulled in 3..
By adding 1 in step 4, you are counting the number of occurrences of a specific mark.

Split string to 140 char chunks

This is my function:
char** split_string(char* message){
int i = 0;
int j = 0;
int numberOfMsgs = 0;
int charsInLastMsg = (int)(strlen(message)%140);
if((int)strlen(message) > 140*4){
return NULL;
}
if((int)(strlen(message)%140)){
numberOfMsgs = (int)(strlen(message)/140) + 1;
}
else{
numberOfMsgs = (int)(strlen(message)/140);
}
printf("message length = %d, we will have %d messages, and last msg will have %d characters\n", (int)strlen(message), numberOfMsgs, charsInLastMsg);
char **m = malloc(numberOfMsgs * sizeof(char*));
for (j =0 ; j <= numberOfMsgs; j++){
m[j] = malloc(141 * sizeof(char));
}
for(i=0;i<numberOfMsgs;i++){
if(i == numberOfMsgs - 1){
memcpy(m[i], message + (140*i), charsInLastMsg);
m[i][charsInLastMsg] = '\0';
}
else{
memcpy(m[i], message + (140*i), 140);
m[i][140] = '\0';
}
printf("m%d = %s\n", i, m[i]);
}
return m;
}
Which I'm calling like this:
char* message = "1, 2, 3, 4, 5, 6, 7, 8, 9 and 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100.";
int i=0;
char** m = split_string(message);
while(*m){
printf("string%d = %s\n", i, m[i]); //Problem at this line.
m++;
}
But, when I run it, I'm getting a segmentation fault at the line indicated above. If I don't print, the program runs fine, so I think the function split_string() is alright.
What am I doing wrong? I'm a newbie, plz help.
/************************************EXPECTED O/P**********************************/
I want the string to be split into 140 char strings as below:
string0 = 1, 2, 3, 4, 5, 6, 7, 8, 9 and 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36
string1 = , 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71
string2 = , 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100.
There are several issues in your code. You have already fixed some.
Your client code
while (*m) {
printf("string%d = %s\n", i, *m);
i++;
m++;
}
(where I have taken the liberty to replace m[i] with i always 0 with *m) suggests that the char-pointer array m is NULL-terminated, i.e. that a NULL pointer indicates the end of the string list. (Much like a '\0' character indicates the end of a string.)
But your function split_string doesn't put a NULL pointer at the end: Your client code will read beyond valid memory.
char **m = malloc(numberOfMsgs * sizeof(char*));
Here, you should allocate (numberOfMsgs + 1) strings, one extra for the NULL.
for (j =0 ; j <= numberOfMsgs; j++){
m[j] = malloc(141 * sizeof(char));
}
Here, you should only allocate numberOfMsgs strings. The NULL string doesn't have to be allocated, just be set to NULL:
m[numberOfMsgs] = NULL;
Finally, you should free the allocated memory. In your case, you can't do that, because you have incremented (and thus changed) the base pointer m. The OS can't free the memory, because the new m isn't registered by the memory allocator.
So, for example:
char **m = split_string(message, 140);
int i = 0;
while (m[i]) {
printf("%d: '%s'\n", i, m[i]);
free(m[i]);
i++;
}
free(m);
That is the problem working with arrays, the information about its size should be stored somewhere, you can never know looking at a char ** how many members it has.
That is why null-terminated strings (c strings) exist, the NULL char marks its end, so you have to iterate through the whole string until you find NULL to know it's length.
Anyway, I´d suggest you modify your split_string() function to:
char** split_string(char* message, size_t * n_msgs) {
//...
*n_msgs = numberOfMsgs;
///
}
And then:
size_t msgs = 0;
char** m = split_string(message, &msgs);
//...
Your while loop is an infinite loop. You are testing the expression *m which never changes, so you will keep increasing i and eventually m[i] will refer to memory that has not been allocated.
You should change for (j =0 ; j <= numberOfMsgs; j++){
m[j] = malloc(141 * sizeof(char));
to
for (j =0 ; j < numberOfMsgs; j++){
m[j] = malloc(141 * sizeof(char));

Knapsack code - not working for some cases

My code is as the following:
#include<stdio.h>
int max(int a,int b)
{
return a>b?a:b;
}
int Knapsack(int items,int weight[],int value[],int maxWeight)
{
int dp[items+1][maxWeight+1];
/* dp[i][w] represents maximum value that can be attained if the maximum weight is w and
items are chosen from 1...i */
/* dp[0][w] = 0 for all w because we have chosen 0 items */
int iter,w;
for(iter=0;iter<=maxWeight;iter++)
{
dp[0][iter]=0;
}
/* dp[i][0] = 0 for all w because maximum weight we can take is 0 */
for(iter=0;iter<=items;iter++)
{
dp[iter][0]=0;
}
for(iter=1;iter<=items;iter++)
{
for(w=0;w<=maxWeight;w=w+1)
{
dp[iter][w] = dp[iter-1][w]; /* If I do not take this item */
if(w-weight[iter] >=0)
{
/* suppose if I take this item */
dp[iter][w] = max( (dp[iter][w]) , (dp[iter-1][w-weight[iter]])+value[iter]);
}
}
}
return dp[items][maxWeight];
}
int main()
{
int items=9;
int weight[/*items+1*/10]={60, 10, 20, 20, 20, 20, 10, 10, 10};
int value[/*items+1*/10]={73, 81, 86, 72, 90, 77, 85, 70, 87};
int iter;
int i;
int maxWeight=180;
for (i=0;i<10;i++){
value[i] = value[i]*weight[i];
}
printf("Max value attained can be %d\n",Knapsack(items,weight,value,maxWeight));
}
My knapsack code is working when
items=12;
int weight[/*items+1*/13]={60, 20, 20, 20, 10, 20, 10, 10, 10, 20, 20, 10};
int value[/*items+1*/13]={48, 77, 46, 82, 85, 43, 49, 73, 65, 48, 47, 51};
where it returned the correct output 7820.
But it doesn't returned the correct output when
items=9;
int weight[/*items+1*/10]={60, 10, 20, 20, 20, 20, 10, 10, 10};
int value[/*items+1*/10]={73, 81, 86, 72, 90, 77, 85, 70, 87};
where it returned the output 9730, the correct output should be 14110.
From observation, the program somehow skipped the 1st value (weight=60, value =73).
I have checked the code several times, but I just cant find what's wrong.
Can someone explain to me why? Thank you!
In your code, you are trying to access out of bounds index for weight and value array. When iter reaches value 9, weight[iter] and value[iter] becomes out of bounds index. I guess, in C you simply get some garbage value for out of index access, but in Java, that will throw an exception. Change the code in your inner for loop to:
dp[iter][w] = dp[iter-1][w]; /* If I do not take this item */
if(w-weight[iter - 1] >=0)
{
/* suppose if I take this item */
dp[iter][w] = maximum( (dp[iter][w]) , (dp[iter-1][w-weight[iter - 1]])+value[iter - 1]);
}
and it will work fine.
int weight[/*items+1*/10]={60, 10, 20, 20, 20, 20, 10, 10, 10};
int value[/*items+1*/10]={73, 81, 86, 72, 90, 77, 85, 70, 87};
Your arrays are of length 10, but you are filling only 9 entries. Hence the last entry gets filled to 0. How to initialize all members of an array to the same value?
int weight[/*items+1*/10]={60, 10, 20, 20, 20, 20, 10, 10, 10, 0};
int value[/*items+1*/10]={73, 81, 86, 72, 90, 77, 85, 70, 87, 0};
But you are trying to access the indices (1 to 9) in your algorithm.
Instead try filling all entries:
int weight[/*items+1*/10]={0, 60, 10, 20, 20, 20, 20, 10, 10, 10};
int value[/*items+1*/10]={0, 73, 81, 86, 72, 90, 77, 85, 70, 87};
EDIT:
The first case gives correct output since in that case the first entry is not included in the optimal solution.

Fastest dithering / halftoning library in C

I'm developing a custom thin-client server that serves rendered webpages to its clients. Server is running on multicore Linux box, with Webkit providing the html rendering engine.
The only problem is the fact that clients display is limited with a 4bit (16 colors) grayscale palette. I'm currently using LibGraphicsMagick to dither images (RGB->4bit grayscale), which is an apparent bottleneck in the server performance. Profiling shows that more than 70% of time is spent running GraphicsMagick dithering functions.
I've explored stackoverflow and the Interwebs for a good high performance solution, but it seems that nobody did any benchmarks on various image manipulation libraries and dithering solutions.
I would be more that happy to find out:
What are the highest performance libraries in regards to dithering / halftoning / quantizing RGB images to 4bit grayscale.
Are there any specilized dithering libs or any public domain code snippets that you could point me to?
What libraries do you prefer for manipulating graphics in regards to high performance?
C language libraries are prefered.
Dithering is going to take quite a bit of time depending on the algorithm chosen.
It's fairly trivial to implement Bayer (Matrix) and Floyd-Steinberg (Diffusion) dithering.
Bayer filtering can be made extremely fast when coded with with MMX/SSE to process parallel pixels. You may also be able to do the dithering / conversion using a GPU shader.
FWIW, you're already using GraphicsMagick but there's an entire list of OSS graphics libraries here
From the list provided by Adisak, without any testing, I would bet on AfterImage. The Afterstep people are obsessed with speed, and also described a clever algorithm.
You could take an alternative approach, if your server could be equipped with a decent PCI-express graphics card featuring OpenGL. Here are some specs from Nvidia. Search for "index mode". What you could do is select a 16 or 256 color display mode, render your image as a texture on a flat polygon (like the side of cube) and then read the frame back.
When reading a frame from an OpenGL card, it is important that bandwidth is good from the card, hence the need for PCI-express. As the documentation says, you also have to choose your colors in indexed mode for decent effects.
I know it's not a C library, but this got me curious about what's available for .NET to do error-diffusion which I used some 20 years ago on a project. I found this and specifically this method.
But to try be helpful :) I found this C library.
Here is an implementation of the Floyd-Steinberg method for half-toning:
#include <opencv2/opencv.hpp>
using namespace cv;
int main(){
uchar scale = 128; // change this parameter to 8, 32, 64, 128 to change the dot size
Mat img = imread("../halftone/tom.jpg", CV_LOAD_IMAGE_GRAYSCALE);
for (int r=1; r<img.rows-1; r++) {
for (int c=1; c<img.cols-1; c++) {
uchar oldPixel = img.at<uchar>(r,c);
uchar newPixel = oldPixel / scale * scale;
img.at<uchar>(r,c) = newPixel;
int quantError = oldPixel - newPixel;
img.at<uchar>(r+1,c) += 7./16. * quantError;
img.at<uchar>(r-1,c+1) += 3./16. * quantError;
img.at<uchar>(r,c+1) += 5./16. * quantError;
img.at<uchar>(r+1,c+1) += 1./16. * quantError;
}
}
imshow("halftone", img);
waitKey();
}
Here is the solution you are looking for.
This is a C function that performs Ordered Dither (Bayer) with a parameter for colors.
It is fast enough to be used in realtime processing.
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef CLAMP
// This produces faster code without jumps
#define CLAMP( x, xmin, xmax ) (x) = MAX( (xmin), (x) ); \
(x) = MIN( (xmax), (x) )
#define CLAMPED( x, xmin, xmax ) MAX( (xmin), MIN( (xmax), (x) ) )
#endif
const int BAYER_PATTERN_16X16[16][16] = { // 16x16 Bayer Dithering Matrix. Color levels: 256
{ 0, 191, 48, 239, 12, 203, 60, 251, 3, 194, 51, 242, 15, 206, 63, 254 },
{ 127, 64, 175, 112, 139, 76, 187, 124, 130, 67, 178, 115, 142, 79, 190, 127 },
{ 32, 223, 16, 207, 44, 235, 28, 219, 35, 226, 19, 210, 47, 238, 31, 222 },
{ 159, 96, 143, 80, 171, 108, 155, 92, 162, 99, 146, 83, 174, 111, 158, 95 },
{ 8, 199, 56, 247, 4, 195, 52, 243, 11, 202, 59, 250, 7, 198, 55, 246 },
{ 135, 72, 183, 120, 131, 68, 179, 116, 138, 75, 186, 123, 134, 71, 182, 119 },
{ 40, 231, 24, 215, 36, 227, 20, 211, 43, 234, 27, 218, 39, 230, 23, 214 },
{ 167, 104, 151, 88, 163, 100, 147, 84, 170, 107, 154, 91, 166, 103, 150, 87 },
{ 2, 193, 50, 241, 14, 205, 62, 253, 1, 192, 49, 240, 13, 204, 61, 252 },
{ 129, 66, 177, 114, 141, 78, 189, 126, 128, 65, 176, 113, 140, 77, 188, 125 },
{ 34, 225, 18, 209, 46, 237, 30, 221, 33, 224, 17, 208, 45, 236, 29, 220 },
{ 161, 98, 145, 82, 173, 110, 157, 94, 160, 97, 144, 81, 172, 109, 156, 93 },
{ 10, 201, 58, 249, 6, 197, 54, 245, 9, 200, 57, 248, 5, 196, 53, 244 },
{ 137, 74, 185, 122, 133, 70, 181, 118, 136, 73, 184, 121, 132, 69, 180, 117 },
{ 42, 233, 26, 217, 38, 229, 22, 213, 41, 232, 25, 216, 37, 228, 21, 212 },
{ 169, 106, 153, 90, 165, 102, 149, 86, 168, 105, 152, 89, 164, 101, 148, 85 }
};
// This is the ultimate method for Bayer Ordered Diher with 16x16 matrix
// ncolors - number of colors diapazons to use. Valid values 0..255, but interesed are 0..40
// 1 - color (1 bit per color plane, 3 bits per pixel)
// 3 - color (2 bit per color plane, 6 bits per pixel)
// 7 - color (3 bit per color plane, 9 bits per pixel)
// 15 - color (4 bit per color plane, 12 bits per pixel)
// 31 - color (5 bit per color plane, 15 bits per pixel)
void makeDitherBayerRgbNbpp( BYTE* pixels, int width, int height, int ncolors ) noexcept
{
int divider = 256 / ncolors;
for( int y = 0; y < height; y++ )
{
const int row = y & 15; // y % 16
for( int x = 0; x < width; x++ )
{
const int col = x & 15; // x % 16
const int t = BAYER_PATTERN_16X16[col][row];
const int corr = (t / ncolors);
const int blue = pixels[x * 3 + 0];
const int green = pixels[x * 3 + 1];
const int red = pixels[x * 3 + 2];
int i1 = (blue + corr) / divider; CLAMP( i1, 0, ncolors );
int i2 = (green + corr) / divider; CLAMP( i2, 0, ncolors );
int i3 = (red + corr) / divider; CLAMP( i3, 0, ncolors );
// If you want to compress the image, use the values of i1,i2,i3
// they have values in the range 0..ncolors
// So if the ncolors is 4 - you have values: 0,1,2,3 which is encoded in 2 bits
// 2 bits for 3 planes == 6 bits per pixel
pixels[x * 3 + 0] = CLAMPED( i1 * divider, 0, 255 ); // blue
pixels[x * 3 + 1] = CLAMPED( i2 * divider, 0, 255 ); // green
pixels[x * 3 + 2] = CLAMPED( i3 * divider, 0, 255 ); // red
}
pixels += width * 3;
}
}
In your case, you need to call the function with parameter ncolors=4
This means that each color plane (for grayscale it is 1 plane) will use 4 bits per pixel.
So, you have to call:
makeDitherBayerRgbNbpp( pixels, width, height, 4 );
The input pixels are in BGR format.
The output pixels are also in BGR format for visualisation purposes.
To obtain the bits, you have to replace this code:
pixels[x * 3 + 0] = CLAMPED( i1 * divider, 0, 255 ); // blue
pixels[x * 3 + 1] = CLAMPED( i2 * divider, 0, 255 ); // green
pixels[x * 3 + 2] = CLAMPED( i3 * divider, 0, 255 ); // red
With something like this:
out.writeBit( i1 ); // blue
out.writeBit( i2 ); // green
out.writeBit( i3 ); // red
Here is a sample picture with your parameters (4bit grayscale)
For more dithering source code and demo app, you can see here

Resources